﻿using System.Text;
using System.Data.SqlClient;

using System;
using System.Timers;
using System.Collections;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using System.Configuration;
using System.Collections.Generic;
using System.Data;
using System.Xml;
using System.Drawing;
using System.Reflection;
using Reborn_Server.App1AppHandler;
using System.IO;
using Reborn_Server;
using System.Net.Sockets;
using Reborn_WorldServer;
using Reborn_WorldServer.TransferCharacters;
using Reborn_WorldServer.PendingTells;
using Reborn_WorldServer.App1AppHandler;
using System.Diagnostics;

namespace App1AppHandler
{
    public class AppHandler2
    {
        public volatile List<Map> Maps = new List<Map>();

        //public System.Collections.ArrayList LockItems = ArrayList.Synchronized(new System.Collections.ArrayList());
        public MapLocks mapLocks = new MapLocks();

        //SERVER MASTER ITEM LIST
        public Dictionary<int, Loot> Items = new Dictionary<int, Loot>();
        public Dictionary<int, SpellIcon> Spells = new Dictionary<int, SpellIcon>();
        public Dictionary<int, WeaponSkill> WeaponSkills = new Dictionary<int, WeaponSkill>();
        public Dictionary<int, Recipie> Recipies = new Dictionary<int, Recipie>();

        //Contains a template set of creatures stored by Database ID. These are not the same reference as creatures in game.
        public Dictionary<int, Creature> AllCreatures = new Dictionary<int, Creature>();

        //UNIQUE ID GENERATOR FOR ALL ITEMS, CREATURES, & CREATURE GROUPS
        public ItemIDGenerator ItemIDGen = new ItemIDGenerator();

        public RandomGenerator random = new RandomGenerator();

        private List<MapName> MapNames = new List<MapName>();

        public AppHandler2()
        {
            AppHandler2 app2 = this;

            //LOAD ITEMS
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Items_SelectAll", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();

            //try
            //{
            while (SDR.Read())
            {
                //Debug.Print(SDR["ID"].ToString());

                //if (SDR["ID"].ToString() == "3")
                //{
                //    int yyy = 0;
                //}

                Loot NewLootItem = new Loot(app2);
                if (SDR["ItemType"].ToString() == "Equipment")
                {
                    Equipment NewItem = new Equipment(app2);
                    if (SDR["Agility"] != DBNull.Value)
                        NewItem.Agility = int.Parse(SDR["Agility"].ToString());
                    if (SDR["Dexterity"] != DBNull.Value)
                        NewItem.Dexterity = int.Parse(SDR["Dexterity"].ToString());
                    if (SDR["Intelligence"] != DBNull.Value)
                        NewItem.Intelligence = int.Parse(SDR["Intelligence"].ToString());
                    if (SDR["Strength"] != DBNull.Value)
                        NewItem.Strength = int.Parse(SDR["Strength"].ToString());
                    if (SDR["Wisdom"] != DBNull.Value)
                        NewItem.Wisdom = int.Parse(SDR["Wisdom"].ToString());
                    if (SDR["Slot"] != DBNull.Value)
                        NewItem.Slot = SDR["Slot"].ToString();
                    if (SDR["Armor"] != DBNull.Value)
                        NewItem.Armor = int.Parse(SDR["Armor"].ToString());
                    if (SDR["Material"] != DBNull.Value)
                        NewItem.Material = SDR["Material"].ToString();

                    if (SDR["HP"] != DBNull.Value)
                        NewItem.HP = int.Parse(SDR["HP"].ToString());
                    if (SDR["HP_Regen"] != DBNull.Value)
                        NewItem.HP_Regen = int.Parse(SDR["HP_Regen"].ToString());
                    if (SDR["Stam"] != DBNull.Value)
                        NewItem.Stam = int.Parse(SDR["Stam"].ToString());
                    if (SDR["Stam_Regen"] != DBNull.Value)
                        NewItem.Stam_Regen = int.Parse(SDR["Stam_Regen"].ToString());
                    if (SDR["Mana"] != DBNull.Value)
                        NewItem.Mana = int.Parse(SDR["Mana"].ToString());
                    if (SDR["Mana_Regen"] != DBNull.Value)
                        NewItem.Mana_Regen = int.Parse(SDR["Mana_Regen"].ToString());

                    if (SDR["ResistFire"] != DBNull.Value)
                        NewItem.ResistFire = int.Parse(SDR["ResistFire"].ToString());
                    if (SDR["ResistIce"] != DBNull.Value)
                        NewItem.ResistIce = int.Parse(SDR["ResistIce"].ToString());
                    if (SDR["ResistHoly"] != DBNull.Value)
                        NewItem.ResistHoly = int.Parse(SDR["ResistHoly"].ToString());
                    if (SDR["ResistUnholy"] != DBNull.Value)
                        NewItem.ResistUnholy = int.Parse(SDR["ResistUnholy"].ToString());
                    if (SDR["ResistMagic"] != DBNull.Value)
                        NewItem.ResistMagic = int.Parse(SDR["ResistMagic"].ToString());
                    if (SDR["ResistPhysical"] != DBNull.Value)
                        NewItem.ResistPhysical = int.Parse(SDR["ResistPhysical"].ToString());

                    if (SDR["WaterMotion"] != DBNull.Value)
                        NewItem.WaterMotion = int.Parse(SDR["WaterMotion"].ToString());

                    NewLootItem = (Loot)NewItem;
                }
                else if (SDR["ItemType"].ToString() == "Weapon")
                {
                    Weapon NewItem = new Weapon(app2);

                    if (SDR["Agility"] != DBNull.Value)
                        NewItem.Agility = int.Parse(SDR["Agility"].ToString());
                    if (SDR["Dexterity"] != DBNull.Value)
                        NewItem.Dexterity = int.Parse(SDR["Dexterity"].ToString());
                    if (SDR["Intelligence"] != DBNull.Value)
                        NewItem.Intelligence = int.Parse(SDR["Intelligence"].ToString());
                    if (SDR["Strength"] != DBNull.Value)
                        NewItem.Strength = int.Parse(SDR["Strength"].ToString());
                    if (SDR["Wisdom"] != DBNull.Value)
                        NewItem.Wisdom = int.Parse(SDR["Wisdom"].ToString());
                    if (SDR["Slot"] != DBNull.Value)
                        NewItem.Slot = SDR["Slot"].ToString();
                    if (SDR["Armor"] != DBNull.Value)
                        NewItem.Armor = int.Parse(SDR["Armor"].ToString());
                    if (SDR["Material"] != DBNull.Value)
                        NewItem.Material = SDR["Material"].ToString();

                    if (SDR["HP"] != DBNull.Value)
                        NewItem.HP = int.Parse(SDR["HP"].ToString());
                    if (SDR["HP_Regen"] != DBNull.Value)
                        NewItem.HP_Regen = int.Parse(SDR["HP_Regen"].ToString());
                    if (SDR["Stam"] != DBNull.Value)
                        NewItem.Stam = int.Parse(SDR["Stam"].ToString());
                    if (SDR["Stam_Regen"] != DBNull.Value)
                        NewItem.Stam_Regen = int.Parse(SDR["Stam_Regen"].ToString());
                    if (SDR["Mana"] != DBNull.Value)
                        NewItem.Mana = int.Parse(SDR["Mana"].ToString());
                    if (SDR["Mana_Regen"] != DBNull.Value)
                        NewItem.Mana_Regen = int.Parse(SDR["Mana_Regen"].ToString());

                    if (SDR["ResistFire"] != DBNull.Value)
                        NewItem.ResistFire = int.Parse(SDR["ResistFire"].ToString());
                    if (SDR["ResistIce"] != DBNull.Value)
                        NewItem.ResistIce = int.Parse(SDR["ResistIce"].ToString());
                    if (SDR["ResistHoly"] != DBNull.Value)
                        NewItem.ResistHoly = int.Parse(SDR["ResistHoly"].ToString());
                    if (SDR["ResistUnholy"] != DBNull.Value)
                        NewItem.ResistUnholy = int.Parse(SDR["ResistUnholy"].ToString());
                    if (SDR["ResistMagic"] != DBNull.Value)
                        NewItem.ResistMagic = int.Parse(SDR["ResistMagic"].ToString());
                    if (SDR["ResistPhysical"] != DBNull.Value)
                        NewItem.ResistPhysical = int.Parse(SDR["ResistPhysical"].ToString());

                    if (SDR["Skill"] != DBNull.Value)
                        NewItem.Skill = SDR["Skill"].ToString();

                    NewItem.DmgLow = int.Parse(SDR["DmgLow"].ToString());
                    NewItem.DmgHigh = int.Parse(SDR["DmgHigh"].ToString());
                    NewItem.Speed = decimal.Parse(SDR["Speed"].ToString());
                    NewItem.Accuracy = int.Parse(SDR["Accuracy"].ToString());
                    NewItem.Defense = int.Parse(SDR["Defense"].ToString());
                    NewItem.Melee = bool.Parse(SDR["Melee"].ToString());
                    NewItem.Range = bool.Parse(SDR["Range"].ToString());
                    NewItem.RangeThrows = bool.Parse(SDR["RangeThrows"].ToString());
                    NewItem.ThrowReturns = bool.Parse(SDR["ThrowReturns"].ToString());
                    NewItem.StamCost = int.Parse(SDR["StamCost"].ToString());

                    if (SDR["RangeDistance"] != DBNull.Value)
                        NewItem.RangeDistance = int.Parse(SDR["RangeDistance"].ToString());

                    NewLootItem = (Loot)NewItem;
                }

                NewLootItem.ID = int.Parse(SDR["ID"].ToString());
                NewLootItem.GameUID = -1;
                NewLootItem.CanConsume = bool.Parse(SDR["CanConsume"].ToString());
                NewLootItem.Bag = bool.Parse(SDR["Bag"].ToString());
                NewLootItem.Belt = bool.Parse(SDR["Belt"].ToString());
                NewLootItem.Equip = bool.Parse(SDR["Equip"].ToString());
                if (SDR["ClassName"] != DBNull.Value)
                    NewLootItem.ClassName = SDR["ClassName"].ToString();
                NewLootItem.Description = SDR["Description"].ToString();
                NewLootItem.ImageURL = SDR["ImageURL"].ToString();
                NewLootItem.ItemType = SDR["ItemType"].ToString();
                NewLootItem.Name = SDR["Name"].ToString();
                NewLootItem.PriceHigh = int.Parse(SDR["PriceHigh"].ToString());
                NewLootItem.PriceLow = int.Parse(SDR["PriceLow"].ToString());
                NewLootItem.Weight = decimal.Parse(SDR["Weight"].ToString());

                NewLootItem.BoundTo = System.Convert.ToInt32(SDR["BindType"].ToString());
                
                if (SDR["Lore"] != DBNull.Value)
                    NewLootItem.Lore = bool.Parse(SDR["Lore"].ToString());

                if (SDR["XmlData"] != DBNull.Value)
                    NewLootItem.XmlData = SDR["XmlData"].ToString();

                NewLootItem.timerDestroyInterval = double.Parse(SDR["DestroyMinutes"].ToString()) * 60 * 1000;

                Items.Add(NewLootItem.ID, NewLootItem);
            }
            //}
            //catch (Exception ex1)
            //{
            //    int xxx = 0;
            //}

            SDR.Close();

            foreach (KeyValuePair<int,Loot> loot in Items)
            {
                if (loot.Value is Equipment)
                {
                    Equipment equip = (Equipment)loot.Value;

                    //Get Requirements for this piece of equipment
                    SQLCom = new SqlCommand("Items_Equipment_Requirements_SelectByItemID", MyCon);
                    SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                    SQLCom.Parameters.AddWithValue("@ItemID", equip.ID);
                    SDR = SQLCom.ExecuteReader();

                    while (SDR.Read())
                    {
                        LevelRequirement lr = new LevelRequirement();
                        lr.Skill = SDR["Skill"].ToString();
                        lr.LevelRequired = int.Parse(SDR["LevelRequired"].ToString());
                        lr.Required = bool.Parse(SDR["Required"].ToString());

                        if (lr.Required == true)
                            equip.RequirementsAll.Add(lr);
                        else
                            equip.RequirementsAny.Add(lr);
                    }

                    SDR.Close();
                }
            }

            //MyCon.Close();


            //LOAD Recipies
            SQLCom = new SqlCommand("Recipies_SelectAll", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            //MyCon.Open();
            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                Recipie recipie = new Recipie();
                recipie.ID = int.Parse(SDR["ID"].ToString());
                recipie.Name = SDR["Name"].ToString();
                recipie.Skill = SDR["Skill"].ToString();
                recipie.ReqLevel = int.Parse(SDR["ReqLevel"].ToString());

                Recipies.Add(int.Parse(SDR["ID"].ToString()), recipie);
            }
            SDR.Close();

            //Load Recipies Items
            foreach (KeyValuePair<int, Recipie> recipie in Recipies)
            {
                //Get Requirements for this piece of equipment
                SQLCom = new SqlCommand("Recipies_Items_SelectByRecipieID", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                SQLCom.Parameters.AddWithValue("@RecipieID", recipie.Value.ID);
                SDR = SQLCom.ExecuteReader();

                while (SDR.Read())
                {
                    RecipieItem recipieItem = new RecipieItem();
                    recipieItem.Item = Items[int.Parse(SDR["ItemID"].ToString())];
                    recipieItem.Qty = int.Parse(SDR["Qty"].ToString());
                    recipieItem.IsConsumed = bool.Parse(SDR["IsConsumed"].ToString());

                    bool isReward = bool.Parse(SDR["IsReward"].ToString());
                    if (isReward)
                        recipie.Value.yeildsItems.Add(recipieItem);
                    else
                        recipie.Value.requiredItems.Add(recipieItem);
                }

                SDR.Close();
            }

            //LOAD Spells
            SQLCom = new SqlCommand("Spells_SelectAll", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            //MyCon.Open();
            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                SpellIcon spellIcon = new SpellIcon();
                spellIcon.ID_DB = int.Parse(SDR["ID"].ToString());
                spellIcon.Name = SDR["Name"].ToString();
                spellIcon.ClassName = SDR["ClassName"].ToString();
                spellIcon.CastType = SDR["CastType"].ToString();
                spellIcon.SpellType = SDR["SpellType"].ToString();
                spellIcon.ImageURL = SDR["ImageURL"].ToString();
                spellIcon.Offensive = bool.Parse(SDR["Offensive"].ToString());
                spellIcon.Description = SDR["Description"].ToString();
                spellIcon.ManaCost = int.Parse(SDR["ManaCost"].ToString());
                if (SDR["FieldImageURL"] != DBNull.Value)
                    spellIcon.FieldImageURL = SDR["FieldImageURL"].ToString();
                if (SDR["LevelRequired"] != DBNull.Value)
                    spellIcon.LevelRequired = int.Parse(SDR["LevelRequired"].ToString());
                if (SDR["Cost"] != DBNull.Value)
                    spellIcon.Cost = int.Parse(SDR["Cost"].ToString());
                if (SDR["StackType"] != DBNull.Value)
                    spellIcon.StackType = SDR["StackType"].ToString();

                spellIcon.Skill = SDR["Skill"].ToString();

                Spells.Add(int.Parse(SDR["ID"].ToString()), spellIcon);
            }
            SDR.Close();


            //LOAD Weapon Skills
            SQLCom = new SqlCommand("WeaponSkills_SelectAll", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                WeaponSkill weaponSkill = new WeaponSkill();
                weaponSkill.ID_DB = int.Parse(SDR["ID"].ToString());
                weaponSkill.Name = SDR["Name"].ToString();
                weaponSkill.Description = SDR["Description"].ToString();
                weaponSkill.Skill = SDR["Skill"].ToString();
                weaponSkill.LevelRequired = int.Parse(SDR["LevelRequired"].ToString());
                weaponSkill.Cost = int.Parse(SDR["Cost"].ToString());

                WeaponSkills.Add(int.Parse(SDR["ID"].ToString()), weaponSkill);
            }
            SDR.Close();


            SQLCom = new SqlCommand("MapNames_SelectAll", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                MapName mapName = new MapName();
                mapName.MapID = int.Parse(SDR["MapID"].ToString());
                mapName.Name = SDR["MapDisplayName"].ToString();

                MapNames.Add(mapName);
            }
            SDR.Close();
            SDR.Dispose();
            MyCon.Close();
            MyCon.Dispose();
        }

        public void AppDisconnect(ClientSocketData socketPacket)
        {
            AppHandler2 app = this;
            Character CharToRemove = socketPacket._character;

            //No character was created, do nothing
            if (CharToRemove == null)
                return;

            LockItem lockItem = Managers.GameHandler.GetLockItem(CharToRemove.MapID, CharToRemove.Instance);
            lock (lockItem.LockObj)
            {
                //If the character has already been removed, dont start the drop timer.
                if (Managers.characterManager.getCharacter(CharToRemove.ID) != null)
                    CharToRemove.startDropTimer();
            }
        }

        public string ExitGame(Character character)
        {
            if (character.ExitSeconds > 0)
            {
                Message msg = new Message();
                msg.Type = "server";
                msg.CreatureID = character.CreatureID;
                msg.Text = "You may not exit for " + character.ExitSeconds.ToString() + " second(s)";
                character.AddMessage(msg);
                return "false";
            }
            else
            {
                character.Timer_Drop_Elapsed(null, null);
                character.ClientSocket._character = null;
                return "true";
            }
        }

        public string Logout(Character character)
        {
            Managers.characterManager.removeCharacter(character);

            return "true";
        }

        public Character Login(string Email, string Password, out string LoginStatus)
        {
            LoginStatus = "";

            AppHandler2 app = this;

            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Users_Login", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            SQLCom.Parameters.AddWithValue("@Email", Email);
            SQLCom.Parameters.AddWithValue("@Password", Password);
            SQLCom.Parameters.Add("@Return_Value", System.Data.SqlDbType.Int);
            SQLCom.Parameters["@Return_Value"].Direction = System.Data.ParameterDirection.ReturnValue;
            MyCon.Open();
            SQLCom.ExecuteNonQuery();
            MyCon.Close();
            MyCon.Dispose();

            int Result = int.Parse(SQLCom.Parameters["@Return_Value"].Value.ToString());

            //Invalid Credentials
            if (Result == 0)
            {
                LoginStatus = "Invalid";
                return null;
            }

            Character MyCharacter = new Character(app);
            MyCharacter.UserID = Result;

            //Valid Credentials
            if (Result > 0)
            {
                //Check if logged in
                if (Managers.characterManager.characterExists(Result))
                {
                    LoginStatus = "LoggedIn";
                    return null;
                }

                MyCharacter.UserID = Result;
                Managers.characterManager.addCharacter(MyCharacter);
                
                return MyCharacter;
            }
            //Valid Credentials, but reset password used
            else 
            {
                //Check if logged in
                if (Managers.characterManager.characterExists(Result))
                {
                    LoginStatus = "LoggedIn";
                    return null;
                }

                MyCharacter.UserID = Result * -1;
                Managers.characterManager.addCharacter(MyCharacter);

                LoginStatus = "ResetPassword";
                return MyCharacter;
            }
        }

        public string MapNames_Select()
        {
            try
            {
                DataSet DS = new DataSet("MyData");
                SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
                SqlCommand SQLCom = new SqlCommand("MapNames_SelectAll", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                SqlDataAdapter SDA = new SqlDataAdapter(SQLCom);
                SDA.Fill(DS, "AllData");
                return DS.GetXml();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        public string GetMapName(int ID)
        {
            foreach (MapName mapName in MapNames)
            {
                if (mapName.MapID == ID)
                    return mapName.Name;
            }
            return "Offline";
        }
        public string GetInstanceName(int ID)
        {
            if (ID == 1)
                return "Antares";
            else if (ID == 2)
                return "Betelgeuse";
            else if (ID == 3)
                return "Canopus";
            else if (ID == 4)
                return "Deneb";

            return "Offline";
        }

        public string Characters_Select(int UserID)
        {
            List<Character> MyCharacters = new List<Character>();
            AppHandler2 app = this;

            try
            {
                SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
                SqlCommand SQLCom = new SqlCommand("Characters_Select", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Parameters.AddWithValue("@UserID", UserID);

                MyCon.Open();
                SqlDataReader SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    Character MyCharacter = new Character(app);

                    //Set HP before ID or update will be sent out due to HP change
                    MyCharacter.MaxHPBase = int.Parse(SDR["MaxHP"].ToString());
                    MyCharacter.HP = int.Parse(SDR["HP"].ToString());

                    MyCharacter.ID = int.Parse(SDR["ID"].ToString());
                    MyCharacter.Name = SDR["Name"].ToString();
                    MyCharacter.Gender = SDR["Gender"].ToString();
                    MyCharacter.ImageURL = SDR["ImageURL"].ToString();
                    MyCharacter.Stamina = int.Parse(SDR["Stamina"].ToString());
                    MyCharacter.Mana = int.Parse(SDR["Mana"].ToString());
                    MyCharacter.Strength = int.Parse(SDR["Strength"].ToString());
                    MyCharacter.Dexterity = int.Parse(SDR["Dexterity"].ToString());
                    MyCharacter.Agility = int.Parse(SDR["Agility"].ToString());
                    MyCharacter.Intelligence = int.Parse(SDR["Intelligence"].ToString());
                    MyCharacter.Wisdom = int.Parse(SDR["Wisdom"].ToString());
                    MyCharacter.MapID = int.Parse(SDR["LastMapID"].ToString());
                    MyCharacter.Instance = int.Parse(SDR["LastInstance"].ToString());
                    MyCharacter.Faction = SDR["Faction"].ToString();

                    MyCharacters.Add(MyCharacter);
                }

                SDR.Close();
                SDR.Dispose();

                MyCon.Close();
                MyCon.Dispose();

                string result = "";

                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

                xmldoc.WriteStartElement("selectcharacters_result");
                string innerXml = "";
                foreach (Character character in MyCharacters)
                {
                    innerXml = innerXml + character.toXML(character);
                }
                xmldoc.WriteRaw(innerXml);

                xmldoc.WriteEndElement();
                xmldoc.Flush();

                xmldoc.Close();

                stringWriter.Flush();

                result = stringWriter.ToString();

                return result;
            }
            catch (Exception ex)
            {
                Character MyCharacter = new Character(app);
                MyCharacter.Name = ex.Message;
                MyCharacters = new List<Character>();
                MyCharacters.Add(MyCharacter);
                return MyCharacters[0].toXML(MyCharacter);
            }
        }

        public string Characters_Insert(int UserID, string Name, string CorpseImageURL, string ImageURL, string Gender, int Strength, int Dexterity, int Agility, int Intelligence, int Wisdom)
        {
            try
            {
                SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
                SqlCommand SQLCom = new SqlCommand("Characters_Insert", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                SQLCom.Parameters.AddWithValue("@UserID", UserID);
                SQLCom.Parameters.AddWithValue("@Name", Name);
                SQLCom.Parameters.AddWithValue("@ImageURL", ImageURL);
                SQLCom.Parameters.AddWithValue("@CorpseImageURL", CorpseImageURL);
                SQLCom.Parameters.AddWithValue("@Gender", Gender);
                SQLCom.Parameters.AddWithValue("@Strength", Strength);
                SQLCom.Parameters.AddWithValue("@Dexterity", Dexterity);
                SQLCom.Parameters.AddWithValue("@Agility", Agility);
                SQLCom.Parameters.AddWithValue("@Intelligence", Intelligence);
                SQLCom.Parameters.AddWithValue("@Wisdom", Wisdom);


                SQLCom.Parameters.Add("Result", System.Data.SqlDbType.Int);
                SQLCom.Parameters["Result"].Direction = System.Data.ParameterDirection.ReturnValue;
                MyCon.Open();
                SQLCom.ExecuteNonQuery();
                MyCon.Close();
                MyCon.Dispose();
                return SQLCom.Parameters["Result"].Value.ToString();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        public string Characters_Delete(int ID)
        {
            try
            {
                SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
                SqlCommand SQLCom = new SqlCommand("Characters_Delete", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                SQLCom.Parameters.AddWithValue("@ID", ID);

                MyCon.Open();
                SQLCom.ExecuteNonQuery();
                MyCon.Close();
                MyCon.Dispose();
                return "true";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        public string Characters_Rename(int ID, string Name)
        {
            try
            {
                SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
                SqlCommand SQLCom = new SqlCommand("Characters_Rename", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

                SQLCom.Parameters.AddWithValue("@ID", ID);
                SQLCom.Parameters.AddWithValue("@Name", Name);

                SQLCom.Parameters.Add("Result", System.Data.SqlDbType.Int);
                SQLCom.Parameters["Result"].Direction = System.Data.ParameterDirection.ReturnValue;

                MyCon.Open();
                SQLCom.ExecuteNonQuery();
                MyCon.Close();
                MyCon.Dispose();
                return SQLCom.Parameters["Result"].Value.ToString();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        public bool EnterGame(ClientSocketData clientSocket, int UserID, int CharacterID,int MapID, int Instance, int MapX, int MapY, bool IsTransfer, string clientVersion)
        {
            AppHandler2 app = this; 

            Character MyCharacter = new Character(app);
            MyCharacter.UserID = UserID;
            MyCharacter.ClientSocket = clientSocket;
            clientSocket._character = MyCharacter;

            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Characters_SelectByID", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@ID", CharacterID);

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();

            int BankCoins = 0;

            //GET CHARACTER

            int HP = 0;
            int Stam = 0;
            int Mana = 0;
            while (SDR.Read())
            {
                HP = int.Parse(SDR["HP"].ToString());
                Stam = int.Parse(SDR["Stamina"].ToString());
                Mana = int.Parse(SDR["Mana"].ToString());

                //Update HP before ID or update will be sent out prematurely
                MyCharacter.MaxHPBase = int.Parse(SDR["MaxHP"].ToString());
                MyCharacter.MaxStaminaBase = int.Parse(SDR["MaxStamina"].ToString());
                MyCharacter.MaxManaBase = int.Parse(SDR["MaxMana"].ToString());

                MyCharacter.ID = int.Parse(SDR["ID"].ToString());
                MyCharacter.CreatureID = ItemIDGen.GetCreatureUID();
                MyCharacter.UserID = int.Parse(SDR["UserID"].ToString());
                MyCharacter.Name = SDR["Name"].ToString();
                MyCharacter.Gender = SDR["Gender"].ToString();
                MyCharacter.GM = bool.Parse(SDR["GM"].ToString());

                if (MyCharacter.Gender == "Male")
                    MyCharacter.SoundDeath = "MaleScream";
                else
                    MyCharacter.SoundDeath = "FemaleScream";

                MyCharacter.ImageURL = SDR["ImageURL"].ToString();
                MyCharacter.Faction = SDR["Faction"].ToString();
                
                
                MyCharacter.Strength = int.Parse(SDR["Strength"].ToString());
                MyCharacter.Dexterity = int.Parse(SDR["Dexterity"].ToString());
                MyCharacter.Agility = int.Parse(SDR["Agility"].ToString());
                MyCharacter.Intelligence = int.Parse(SDR["Intelligence"].ToString());
                MyCharacter.Wisdom = int.Parse(SDR["Wisdom"].ToString());
                
                MyCharacter.MapID = MapID;
                MyCharacter.Instance = Instance;
                
                MyCharacter.Coins = int.Parse(SDR["NumCoins"].ToString());
                MyCharacter.CorpseImageURL = SDR["CorpseImageURL"].ToString();
                BankCoins = int.Parse(SDR["BankCoins"].ToString());

                MyCharacter.CreatureType = "Character";

                //Initialize the skill manager before adding the equipment
                MyCharacter.skillManager = new SkillManager(MyCharacter);

                //Initialize the equipment before setting left and right hand
                MyCharacter.equipManager = new EquipmentManager(MyCharacter);
                MyCharacter.UpdateEquipment();

                if (SDR["LeftHand"] != DBNull.Value)
                    MyCharacter.LeftHand = CreateItem(int.Parse(SDR["LeftHand"].ToString()), int.Parse(SDR["LeftHand_BoundTo"].ToString()));
                if (SDR["RightHand"] != DBNull.Value)
                    MyCharacter.RightHand = CreateItem(int.Parse(SDR["RightHand"].ToString()), int.Parse(SDR["RightHand_BoundTo"].ToString()));

                MyCharacter.showTips = bool.Parse(SDR["ShowTips"].ToString());

                MyCharacter.BindMapID = int.Parse(SDR["BindMapID"].ToString()); 
                MyCharacter.BindMapX = int.Parse(SDR["BindMapX"].ToString());
                MyCharacter.BindMapY = int.Parse(SDR["BindMapY"].ToString());
            }

            SDR.Close();

            //Load self defense flags
            SQLCom = new SqlCommand("Characters_SDFlags_Select", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@CharacterID", CharacterID);

            SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                MyCharacter.hateManager.ResumeSDFlag(
                    int.Parse(SDR["FlaggedCharacterID"].ToString()),
                    DateTime.Parse(SDR["Expires"].ToString()));
            }
            SDR.Close();

            if (IsTransfer == false)
            {
                //Get mail count
                SQLCom = new SqlCommand("Characters_Mail_SelectCount", MyCon);
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Parameters.AddWithValue("@CharacterID", CharacterID);

                SDR = SQLCom.ExecuteReader();
                while (SDR.Read())
                {
                    if (SDR["MailItems"].ToString() != "0")
                        MyCharacter.SendMessage("You have " + SDR["MailItems"].ToString() + " mail pieces", "server");
                }
                SDR.Close();
            }

            MyCon.Close();
            MyCon.Dispose();

            //Get lock (this will create the map also)
            LockItem MyLock = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);
            Map CurrentMap = GetMap(MapID, Instance);

            MyCharacter.getColorOverrides();

            //Initialize weapon skill manager
            MyCharacter.weaponSkillManager = new WeaponSkillManager(MyCharacter);
            
            //Initialize the pet manager
            MyCharacter.petManager = new PetManager(MyCharacter);

            //Initializes MyCharacters belt (Creates Items & Sends Update)
            MyCharacter.beltManager = new BeltManager(MyCharacter);

            //Initializes MyCharacters bank (Creates Items)
            MyCharacter.bankManager = new BankManager(MyCharacter);
            MyCharacter.bankManager.BankCoins = BankCoins;
            
            //Initializes the bag (creates items updates UI)
            MyCharacter.bagManager = new BagManager(MyCharacter);

            //Initialize recipies
            MyCharacter.recipieManager = new RecipieManager(MyCharacter);

            //Initialize the chat channel manager
            MyCharacter.chatChannelManager = new ChatChannelManager(MyCharacter);

            //Initialize spells manager
            MyCharacter.spellManager = new SpellManager(MyCharacter);

            //Initialize friends manager
            MyCharacter.friendsManager = new FriendsManager(MyCharacter);

            //Update Karma
            MyCharacter.UpdateKarma(!IsTransfer);

            MyCharacter.HP = HP;
            MyCharacter.Stamina = Stam;
            MyCharacter.Mana = Mana;


            List<MapItem> MyMap = new List<MapItem>();
            List<MapItem> MapItemsToUpdate = new List<MapItem>();
            List<Character> CharactersToUpdate = new List<Character>();

            //Lock Map
            lock (MyLock.LockObj)
            {
                foreach (MapItem mapitem in CurrentMap.MapItems)
                {
                    //Locate Map Items Within Range
                    if (Math.Abs(mapitem.MapX - MapX) <= 8 && Math.Abs(mapitem.MapY - MapY) <= 8)
                    {
                        bool playOpenDoor = false;
                        //Add character to location
                        if (mapitem.MapX == MapX && mapitem.MapY == MapY)
                        {
                            if ((mapitem.TerrainType == "Door" || mapitem.TerrainType == "SDoor") && mapitem.TerrainUrl.IndexOf("Open") == -1)
                            {
                                playOpenDoor = true;
                                if (mapitem.TerrainType == "SDoor")
                                {
                                    mapitem.TerrainUrl = mapitem.TerrainUrl + "_Open";
                                    mapitem.Transparent = true;
                                    mapitem.Motion = 4;
                                    mapitem.timerHexReset.Stop();
                                    mapitem.timerHexReset.Start();
                                }
                                else if (mapitem.TerrainType == "Door")
                                {
                                    mapitem.TerrainUrl = mapitem.TerrainUrl.Replace("Closed", "Open");
                                    mapitem.Transparent = true;
                                }
                            }
                            MyCharacter.SetPosition(mapitem);

                            mapitem.CreaturesBases.Add(MyCharacter);
                            MyCharacter.Update_Character();
                            MapItemsToUpdate.Add(mapitem);
                        }
                        //Add Map Item to List for Update
                        MyMap.Add(mapitem);
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character character = (Character)creatureBase;
                                if (playOpenDoor == true)
                                    character.PlaySound("DoorOpen", MyCharacter.MapX, MyCharacter.MapY);

                                if (character.ID != MyCharacter.ID)
                                    CharactersToUpdate.Add(character);
                            }
                        }
                    }
                }
            }

            lock (MyLock.LockObj)
            {
                MyCharacter.AddMapItems(MyMap, true);
            }

            
            MyCharacter.buffManager.ResumeBuffs();

            lock (MyLock.LockObj)
            {
                //We need to re-set these incase a buff adjusted the max.
                MyCharacter.HP = HP;
                MyCharacter.Stamina = Stam;
                MyCharacter.Mana = Mana;

                //Re update character incase our stats or max stats changed
                MyCharacter.Update_Character();

                foreach (Character character in CharactersToUpdate)
                {
                    character.AddMapItems(MapItemsToUpdate, false);
                }
            }

            //Update the surrounding loot
            CurrentMap.LootMngr.GetLootInArea(MyCharacter);

            Managers.characterManager.addCharacter(MyCharacter);

            MyCharacter.updateWeight();

            MyCharacter.Timer_Regen.Start();
            MyCharacter.Timer_AutoSave.Start();

            if (IsTransfer)
            {
                MyCharacter.Timer_Round_Interval = System.Convert.ToDouble(MyCharacter.MovementSpeed * 1000);
                MyCharacter.Timer_Round_Start();
            }
            else
            {
                Managers.characterManager.sendFriendOnline(MyCharacter.ID);
                MyCharacter.chatChannelManager.sendLoginNotifications();
            }
            
            if (clientVersion != "7.77") 
            {
                MyCharacter.SendMessage("WARNING: Your client is out of date! Please close the game window and delete your temporary internet files", "server");
                MyCharacter.SendMessage("WARNING: Your client is out of date! Please close the game window and delete your temporary internet files", "server");
                MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
            }

            return true;
        }

        public void ConjureCoins(Character character, int coins)
        {
            character.Coins = character.Coins + coins;
            character.Update_Character();
        }

        public void ConjureItem(Character character, int itemId)
        {
            Loot itemToConjure = null;
            try
            {
                itemToConjure = CreateItem(itemId);
            }
            catch
            {
                character.SendMessage("Server: Invalid item ID", "server");
                character.PlaySound("Ding", character.MapX, character.MapY);
                return;
            }

            List<Loot> items = new List<Loot>();
            items.Add(itemToConjure);

            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                if (character.HasInventoryFor(items) == false)
                {
                    character.SendMessage("You do not have inventory space.", "server");
                    return;
                }
                bool updateChar;
                bool updateBag;
                bool updateBelt;
                character.AddToInventory(items, out updateBag, out updateBelt, out updateChar, true);

                if (updateBelt == true)
                    character.beltManager.UpdateBelt();
                if (updateBag == true)
                    character.bagManager.UpdateBag();
                if (updateChar == true)
                {
                    character.Update_Character();

                    Map map = GetMap(character.MapID, character.Instance);
                    List<MapItem> mapitems = map.GetMapItemsWithin(character.MapX,character.MapY,4);

                    foreach (MapItem mapItem in mapitems)
                    {
                        foreach (CreatureBase creatureBase in mapItem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character charToUpdate = (Character)creatureBase;
                                charToUpdate.AddCreatureBase(character);
                            }
                        }
                    }
                }
            }
        }

        public void AddFriend(Character character, string friendName)
        {
            character.friendsManager.AddFriend(friendName);
        }
        public void DeleteFriend(Character character, int friendID)
        {
            character.friendsManager.DeleteFriend(friendID);
        }


        public void removeMail(Character character, int mailID)
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);

            //First lookup the mail item they are trying to delete.
            SqlCommand SQLCom = new SqlCommand("Characters_Mail_SelectByID", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@MailID", mailID);

            int mailCharacterID = -1;
            int coins = 0;

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                mailCharacterID = int.Parse(SDR["CharacterID"].ToString());
                coins = int.Parse(SDR["Coins"].ToString());
            }
            SDR.Close();

            //Ensure that they are the character that owns this mail
            if (mailCharacterID == character.ID)
            {
                //Get attachments
                SQLCom.Parameters.Clear();
                SQLCom.CommandText = "Characters_Mail_Attachments_Select";
                SQLCom.Parameters.AddWithValue("@MailID", mailID);

                List<Loot> itemsToCreate = new List<Loot>();
                SDR = SQLCom.ExecuteReader();

                while (SDR.Read())
                {
                    itemsToCreate.Add(
                        Managers.GameHandler.CreateItem(
                            int.Parse(SDR["ItemID"].ToString()),
                            int.Parse(SDR["ItemBoundTo"].ToString()),
                            true)
                        );
                }
                SDR.Close();

                bool updateCharacter = false;
                bool updateBelt = false;
                bool updateBag = false;

                if (itemsToCreate.Count > 0)
                {
                    if (character.HasInventoryFor(itemsToCreate))
                    {
                        List<Loot> actualItems = new List<Loot>();
                        foreach (Loot l in itemsToCreate)
                            actualItems.Add(CreateItem(l.ID, l.BoundTo));

                        character.AddToInventory(actualItems, out updateBag, out updateBelt, out updateCharacter);
                    }
                    else
                    {
                        

                        try
                        {
                            character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"You do not have enough inventory space available.\" />");
                        }
                        catch { }

                        return;
                    }
                }
                if (coins > 0)
                {
                    character.Coins = character.Coins + coins;
                    updateCharacter = true;
                }

                //Delete mail
                SQLCom.CommandText = "Characters_Mail_Delete";
                SQLCom.Parameters.Clear();
                SQLCom.Parameters.AddWithValue("@ID", mailID);
                SQLCom.ExecuteNonQuery();

                if (updateCharacter)
                    character.Update_Character();
                if (updateBelt)
                    character.beltManager.UpdateBelt();
                if (updateBag)
                    character.bagManager.UpdateBag();

                if (updateCharacter || updateBag || updateBag)
                    character.updateWeight();

                try
                {
                    //Mail sent, send notification + new mail box data. (Our items will have changed if we have attachments, or if we mailed ourselves)

                    character.ClientSocket.socket.BeginSend("<mailresult result=\"true\" message=\"\" >" + character.getMailBox(false) + "</mailresult>");
                }
                catch { }
            }
            else
            {
                try
                {
                    character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"You do not have the items you attempted to delete!\" />");
                }
                catch { }
            }

            MyCon.Close();
            MyCon.Dispose();
        }
        public void deleteMail(Character character, int mailID)
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);

            //First lookup the mail item they are trying to delete.
            SqlCommand SQLCom = new SqlCommand("Characters_Mail_SelectByID", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
            SQLCom.Parameters.AddWithValue("@MailID", mailID);

            int mailCharacterID = -1;

            MyCon.Open();
            SqlDataReader SDR = SQLCom.ExecuteReader();
            while (SDR.Read())
            {
                mailCharacterID = int.Parse(SDR["CharacterID"].ToString());
            }
            SDR.Close();
            SDR.Dispose();

            //Ensure that they are the character that owns this mail
            if (mailCharacterID == character.ID)
            {
                //Delete mail
                SQLCom.CommandText = "Characters_Mail_Delete";
                SQLCom.Parameters.Clear();
                SQLCom.Parameters.AddWithValue("@ID", mailID);
                SQLCom.ExecuteNonQuery();
                

                try
                {
                    //Mail sent, send notification + new mail box data. (Our items will have changed if we have attachments, or if we mailed ourselves)


                    character.ClientSocket.socket.BeginSend("<mailresult result=\"true\" message=\"\" >" + character.getMailBox(false) + "</mailresult>");
                }
                catch { }
            }
            else
            {
                try
                {
                    character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"You do not have the items you attempted to delete!\" />");
                }
                catch { }
            }

            MyCon.Close();
            MyCon.Dispose();
        }
        public void sendMail(Character character, string toCharacter, string subject, string message, int coins, List<long> attachmentGuids)
        {
            //TODO: Inventory scanning & removal is not thread safe!!

            if (subject == "")
                subject = "No Subject";
            if (message == "")
                message = "No Message";

            List<Loot> itemsToAttach = character.getInventoryItems(attachmentGuids);

            //Should not get here, character does not have inventory items they specified.
            if (itemsToAttach == null)
            {
                //Send Failure
                try
                {
                    character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"You do not have the items you attempted to mail!\" />");
                }
                catch { }

                return;
            }
            foreach (Loot item in itemsToAttach)
            {
                if (item.ID < 1)
                {
                    //Send Failure
                    try
                    {
                        character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"You can not mail a " + item.Name + "\" />");
                    }
                    catch { }

                    return;
                }
            }

            //Should not get here, character does not have enough coins.
            if (character.Coins < coins)
            {
                //Send Failure
                try
                {
                    character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"You do not have the coins you attempted to mail!\" />");
                }
                catch { }

                return;
            }

            
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            MyCon.Open();
            SqlTransaction MyTrans = MyCon.BeginTransaction();
            bool commitTransaction = true;

            bool updateBag = false;
            bool updateBelt = false;
            bool updateCharacter = false;

            int mailID = -1;
            int toCharacterId = -1;

            try
            {
                SqlCommand SQLCom = new SqlCommand();
                SQLCom.Connection = MyCon;
                SQLCom.CommandType = System.Data.CommandType.StoredProcedure;
                SQLCom.Transaction = MyTrans;

                SQLCom.CommandText = "Characters_Mail_Insert";
                SQLCom.Parameters.AddWithValue("@ToCharacterName", toCharacter);
                SQLCom.Parameters.AddWithValue("@FromCharacterID", character.ID);
                SQLCom.Parameters.AddWithValue("@Subject", subject);
                SQLCom.Parameters.AddWithValue("@Message", message);
                SQLCom.Parameters.AddWithValue("@Coins", coins);


                SQLCom.Parameters.Add("@ToCharacterID", SqlDbType.Int);
                SQLCom.Parameters["@ToCharacterID"].Direction = ParameterDirection.Output;

                SQLCom.Parameters.Add("@Return_Value", System.Data.SqlDbType.Int);
                SQLCom.Parameters["@Return_Value"].Direction = System.Data.ParameterDirection.ReturnValue;

                SQLCom.ExecuteNonQuery();

                //Get the identity of the new mail item we just inserted so we can add the attachments
                mailID = int.Parse(SQLCom.Parameters["@Return_Value"].Value.ToString());
                toCharacterId = int.Parse(SQLCom.Parameters["@ToCharacterID"].Value.ToString());

                //Bad recipeient
                if (mailID == -1)
                    commitTransaction = false;
                //Add attachments
                else
                {
                    character.RemoveFromInventory(itemsToAttach, out updateBag, out updateBelt, out updateCharacter);
                    
                    if (coins > 0)
                    {
                        character.Coins = character.Coins - coins;
                        updateCharacter = true;
                    }

                    SQLCom.Parameters.Clear();
                    SQLCom.CommandText = "Characters_Mail_Attachments_Insert";
                    
                    SQLCom.Parameters.AddWithValue("@MailID", mailID);

                    SQLCom.Parameters.Add("@ItemID", SqlDbType.Int);
                    SQLCom.Parameters.Add("@ItemBoundTo", SqlDbType.Int);

                    foreach (Loot l in itemsToAttach)
                    {
                        SQLCom.Parameters["@ItemID"].Value = l.ID;
                        SQLCom.Parameters["@ItemBoundTo"].Value = l.BoundTo;
                        SQLCom.ExecuteNonQuery();
                    }
                }

                if (commitTransaction == true)
                    MyTrans.Commit();
                else
                    MyTrans.Rollback();
            }
            catch
            {
                commitTransaction = false;
                MyTrans.Rollback();
            }
            finally
            {
                MyCon.Close();
                MyCon.Dispose();
            }

            try
            {
                if (commitTransaction == true)
                {
                    bool updateWeight = false;
                    if (updateCharacter)
                    {
                        character.Update_Character();
                        updateWeight = true;
                    }
                    if (updateBelt)
                    {
                        character.beltManager.UpdateBelt();
                        updateWeight = true;
                    }
                    if (updateBag)
                    {
                        character.bagManager.UpdateBag();
                        updateWeight = true;
                    }

                    if (updateWeight == true)
                        character.updateWeight();

                    //Mail sent, send notification + new mail box data. (Our items will have changed if we have attachments, or if we mailed ourselves)

                    character.ClientSocket.socket.BeginSend("<mailresult result=\"true\" message=\"Mail sent.\" >" + character.getMailBox(false) + "</mailresult>");

                    Character sendToCharacter = Managers.characterManager.getCharacter(toCharacterId);
                    if (sendToCharacter != null)
                        sendToCharacter.SendMessage("You have new mail.", "server");
                    else
                        Managers.BeginSendToPrimary("<newmail characterid=\"" + toCharacterId.ToString() + "\" />");
                }
                else
                {
                    character.ClientSocket.socket.BeginSend("<mailresult result=\"false\" message=\"Mail could not be delivered: No character named " + toCharacter + ".\" />");
                }
            }
            catch { }
        }

        public void randomRoll(Character character)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);

            lock (lockItem.LockObj)
            {
                Map map = GetMap(character.MapID, character.Instance);

                List<MapItem> MapItemsInRange = new List<MapItem>();
                foreach (MapItem mapitem in map.MapItems)
                {
                    if (mapitem.MapX - character.MapX >= -4 && mapitem.MapX - character.MapX <= 4 &&
                        mapitem.MapY - character.MapY >= -4 && mapitem.MapY - character.MapY <= 4)
                    {
                        MapItemsInRange.Add(mapitem);
                    }
                }
                List<Point> Hidden = CreatureAI.FindHidden(character, MapItemsInRange, true);

                List<MapItem> MapItemsNotHidden = new List<MapItem>();
                foreach (MapItem mapitem in MapItemsInRange)
                {
                    bool foundHidden = false;
                    foreach (Point point in Hidden)
                    {
                        if (point.X == mapitem.MapX && point.Y == mapitem.MapY)
                        {
                            foundHidden = true;
                            break;
                        }
                    }
                    if (foundHidden == false)
                        MapItemsNotHidden.Add(mapitem);
                }
                int randomValue = random.Next(1, 101);
                foreach (MapItem mapitem in MapItemsNotHidden)
                {
                    foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                    {
                        if (creatureBase is Character)
                        {
                            Character charToMessage = (Character)creatureBase;
                            charToMessage.SendMessage(character.Name + " rolls a magic die. (" + randomValue.ToString() + ")", "server");
                        }
                    }
                }
            }
        }

        public string BankerOpenWindow(Character character)
        {
            string result = "";

            BankerItems bankerItems = new BankerItems();

            bankerItems.BankerCoins = character.bankManager.BankCoins;
            bankerItems.PlayerCoins = character.Coins;
            bankerItems.BankItems = character.bankManager.getBankCopy();

            if (character.LeftHand != null)
                bankerItems.PlayerItems.Add(character.LeftHand);
            if (character.RightHand != null)
                bankerItems.PlayerItems.Add(character.RightHand);

            List<Loot> characterBag = character.bagManager.getAllBagItems();
            foreach (Loot loot in characterBag)
                bankerItems.PlayerItems.Add(loot);
    
            Loot[] beltLoot = character.beltManager.getBeltLootCopy();
            foreach (Loot loot in beltLoot)
            {
                if (loot != null)
                    bankerItems.PlayerItems.Add(loot);
            }

            result = bankerItems.toXML(character);

            return result;
        }

        public string BankerDepositCoins(Character character, int coins)
        {
            if (character.Coins >= coins)
            {
                character.Coins = character.Coins - coins;
                character.bankManager.BankCoins = character.bankManager.BankCoins + coins;
                character.Update_Character();
                character.updateWeight();
            }
            else
                return "You do not have enough coins";

            return "true";
        }

        public string BankerWithdrawCoins(Character character, int coins)
        {
            if (character.bankManager.BankCoins >= coins)
            {
                character.Coins = character.Coins + coins;
                character.Update_Character();
                character.bankManager.BankCoins = character.bankManager.BankCoins - coins;
                character.updateWeight();
            }
            else
                return "There are not enough coins in the bank";

            return "true";
        }

        public string BankerDepositItem(Character character, long gameUID)
        {
            string result = "";
            AppHandler2 app = this;

            Loot itemToDeposit = null;

            //Check if deposit item is in left hand
            if (character.LeftHand != null && itemToDeposit == null)
            {
                if (character.LeftHand.GameUID == gameUID)
                {
                    itemToDeposit = character.LeftHand;
                    if (itemToDeposit.ID < 0)
                    {
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return "Cannot deposit that item";
                    }

                    character.LeftHand = null;
                    character.Update_Character();
                }
            }
            //Check if deposit item is in right hand
            if (character.RightHand != null && itemToDeposit == null)
            {
                if (character.RightHand.GameUID == gameUID)
                {
                    itemToDeposit = character.RightHand;
                    if (itemToDeposit.ID < 0)
                    {
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return "Cannot deposit that item";
                    }

                    character.RightHand = null;
                    character.Update_Character();
                }
            }
            //check if deposit item is in bag
            if (itemToDeposit == null)
            {
                itemToDeposit = character.bagManager.getBagItem(gameUID);
                if (itemToDeposit != null)
                {
                    if (itemToDeposit.ID < 0)
                    {
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return "Cannot deposit that item";
                    }
                    character.bagManager.removeBagItem(gameUID);
                    character.bagManager.UpdateBag();
                }
            }

            //check if deposit item is in belt
            if (itemToDeposit == null)
            {
                itemToDeposit = character.beltManager.GetBeltItem(gameUID);
                if (itemToDeposit != null)
                {
                    if (itemToDeposit.ID < 0)
                    {
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return "Cannot deposit that item";
                    }
                    character.beltManager.RemoveBeltItem(itemToDeposit.GameUID);
                    character.beltManager.UpdateBelt();
                }
            }

            //if we still havn't found the item return an error
            if (itemToDeposit == null)
                return "Cannot find item to deposit";

            character.bankManager.depositItem(itemToDeposit);
            character.updateWeight();

            result = "true";

            return result;
        }

        public string BankerWithdrawItem(Character character, long gameUID)
        {
            AppHandler2 app = this;
            string result = "";

            Loot ItemToWithdraw = character.bankManager.getItem(gameUID);
            if (ItemToWithdraw == null)
                return "Item is not in your bank";

            if (ItemToWithdraw.Lore == true && character.hasItem(ItemToWithdraw.ID))
                return "You cannot carry any more of those items!";

            //Try to place in bag
            if (ItemToWithdraw.Bag == true && result != "true")
            {
                if (character.bagManager.addBagItem(ItemToWithdraw) == true)
                {
                    character.bagManager.UpdateBag();
                    result = "true";
                }
            }

            //Try to place in belt
            if (ItemToWithdraw.Belt == true && result != "true")
            {
                if (character.beltManager.AddItem(ItemToWithdraw) == true)
                {
                    character.beltManager.UpdateBelt();
                    result = "true";
                }
            }

            //Try to place in left hand
            if (character.LeftHand == null && result != "true")
            {
                character.LeftHand = ItemToWithdraw;
                character.Update_Character();
                result = "true";
            }

            //Try to place in right hand
            if (character.RightHand == null && result != "true")
            {
                character.RightHand = ItemToWithdraw;
                character.Update_Character();
                result = "true";
            }

            if (result == "true")
                character.bankManager.removeItem(gameUID);

            if (result != "true")
                return "No inventory available";

            character.updateWeight();

            return result;
        }

        public void TrainerOpenWindow(Character character, long CreatureID)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                CreatureBase trainer = null;
                foreach (MapItem mapItem in character.currentMapItem.mapItemsWithin4)
                {
                    if (trainer != null)
                        break;

                    if (Math.Abs(mapItem.MapX - character.MapX) <= 2 && Math.Abs(mapItem.MapY - character.MapY) <= 2)
                    {
                        foreach (CreatureBase creatureBase in mapItem.CreaturesBases)
                        {
                            if (creatureBase.CreatureID == CreatureID)
                            {
                                trainer = creatureBase;
                                break;
                            }
                        }
                    }
                }
                if (trainer == null)
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Trainer is to far away.";

                    character.PlaySound("Ding", character.MapX, character.MapY);
                    character.AddMessage(message);
                    return;
                }

                if (trainer is Trainer)
                {
                    Trainer t = (Trainer)trainer;
                    t.OpenTrainerWindow(character);
                }
                else if (trainer.CreatureType.ToLower().IndexOf("trainer") > -1)
                {
                    string trainerType = trainer.CreatureType.Replace("Trainer","");

                    TradeTrainerData tradeData = new TradeTrainerData(character, trainer, trainerType);
                    character.ClientSocket.socket.BeginSend(tradeData.toXML());
                }
                //Should not get here
                else
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = trainer.Name + " is not a Trainer! Please Bug Report";

                    character.PlaySound("Ding", character.MapX, character.MapY);
                    character.AddMessage(message);
                    return;
                }
            }

            
        }

        public void QuestClaimReward(Character character, long CreatureID, int RewardID)
        {
            QuestCreature questCreature = null;

            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                Map CurrentMap = GetMap(character.MapID, character.Instance);
                foreach (MapItem mapitem in CurrentMap.MapItems)
                {
                    if (Math.Abs(mapitem.MapX - character.MapX) <= 4 && Math.Abs(mapitem.MapY - character.MapY) <= 4)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is QuestCreature && creatureBase.CreatureID == CreatureID)
                            {
                                questCreature = (QuestCreature)creatureBase;
                                break;
                            }
                        }
                    }
                    if (questCreature != null)
                        break;
                }
            
                if (questCreature == null)
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Cannot find creature";

                    character.AddMessage(message);
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    return;
                }
                
                //Creature is not ready to give rewards
                if (questCreature.QuestStatus != "Complete")
                    return;

                //Quest does not belong to this player
                if (questCreature.petController != null && questCreature.petController.MasterCreature != character)
                    return;

                //Reward has already been claimed
                if (questCreature.QuestType == "Escort" && questCreature.petController == null)
                    return;

                List<Loot> QuestRewards = new List<Loot>();
                if (questCreature.RewardsAll)
                    QuestRewards = questCreature.RewardItems;
                else
                {
                    foreach (Loot loot in questCreature.RewardItems)
                    {
                        if (loot.ID == RewardID)
                        {
                            QuestRewards.Add(loot);
                            break;
                        }
                    }
                }

                if (character.HasInventoryFor(QuestRewards) == false)
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "You do not have enough inventory available";

                    character.AddMessage(message);
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    return;
                }
                foreach (Loot item in QuestRewards)
                {
                    if (item.Lore == true && character.hasItem(item.ID))
                    {
                        Message message = new Message();
                        message.CreatureID = character.CreatureID;
                        message.Type = "server";
                        message.Text = "You cannot carry any more " + item.Name;

                        character.AddMessage(message);
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return;
                    }
                }

                if (questCreature.petController != null)
                {
                    questCreature.petController = null;

                    questCreature.Timer_EscortChangePosition.Stop();
                    questCreature.Timer_EscortChangePosition.Interval = 1000 * 30;
                    questCreature.Timer_EscortChangePosition.Start();
                }

                bool updateCharacter1 = false;
                bool updateBag1 = false;
                bool updateBelt1 = false;
                List<Loot> collectionItems = questCreature.hasCollectionItems(character);
                if (collectionItems != null)
                {
                    character.RemoveFromInventory(collectionItems, out updateBag1, out updateBelt1, out updateCharacter1);
                }
                else
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "You do not have the required items";

                    character.AddMessage(message);
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    return;
                }

                //Replace the quest creature's rewards with newly generated items
                List<Loot> NewRewards = new List<Loot>();
                for (int x = 0; x < QuestRewards.Count; x++)
                    NewRewards.Add(CreateItem(QuestRewards[x].ID));

                bool updateBag2;
                bool updateBelt2;
                bool updateCharacter2;

                character.AddToInventory(NewRewards, out updateBag2, out updateBelt2, out updateCharacter2);

                if (updateCharacter1 || updateCharacter2)
                    character.Update_Character();
                if (updateBag1 || updateBag2)
                    character.bagManager.UpdateBag();
                if (updateBelt1 || updateBelt2)
                    character.beltManager.UpdateBelt();

                Message msg = new Message();
                msg.CreatureID = character.CreatureID;
                msg.Type = "server";
                msg.Text = "You complete " + questCreature.Name + "\'s Quest";

                character.AddMessage(msg);
                character.PlaySound("SkillUp", character.MapX, character.MapY);

                character.updateWeight();
            }
        }
        public void QuestCreatureAcceptQuest(Character character, long CreatureID)
        {
            QuestCreature questCreature = null;

            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                Map CurrentMap = GetMap(character.MapID, character.Instance);
                foreach (MapItem mapitem in CurrentMap.MapItems)
                {
                    if (Math.Abs(mapitem.MapX - character.MapX) <= 4 && Math.Abs(mapitem.MapY - character.MapY) <= 4)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is QuestCreature && creatureBase.CreatureID == CreatureID)
                            {
                                questCreature = (QuestCreature)creatureBase;
                                break;
                            }
                        }
                    }
                    if (questCreature != null)
                        break;
                }
                if (questCreature == null)
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Cannot find creature";

                    character.AddMessage(message);
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    return;
                }
                if (questCreature.QuestType == "Escort" && questCreature.petController == null)
                    questCreature.AcceptEscort(character);
            }
        }
        public void QuestCreatureOpenWindow(Character character, long CreatureID)
        {
            QuestCreature questCreature = null;

            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                Map CurrentMap = GetMap(character.MapID, character.Instance);
                foreach (MapItem mapitem in CurrentMap.MapItems)
                {
                    if (Math.Abs(mapitem.MapX - character.MapX) <= 4 && Math.Abs(mapitem.MapY - character.MapY) <= 4)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is QuestCreature && creatureBase.CreatureID == CreatureID)
                            {
                                questCreature = (QuestCreature)creatureBase;
                                break;
                            }
                        }
                    }
                    if (questCreature != null)
                        break;
                }
            }
            if (questCreature == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find creature";

                character.AddMessage(message);
                character.PlaySound("Ding", character.MapX, character.MapY);
                return;
            }

            QuestData questData = new QuestData();
            questData.QuestType = questCreature.QuestType;
            questData.QuestStartDialog = questCreature.QuestStartDialog;
            questData.QuestFinishDialog = questCreature.QuestFinishDialog;
            questData.RewardItems = questCreature.RewardItems;
            questData.CreatureID = questCreature.CreatureID;
            questData.CreatureName = questCreature.Name;
            questData.RewardsAll = questCreature.RewardsAll;

            questData.QuestStatus = questCreature.QuestStatus;
            
            //Escort quest has already been completed
            if (questData.QuestStatus == "Complete" && questCreature.QuestType == "Escort" && questCreature.petController == null)
                questData.QuestStatus = "Claimed";

            if (questCreature.petController != null && questCreature.petController.MasterCreature != character)
                questData.AssignedTo = questCreature.petController.MasterCreature.Name;

            if (questData.QuestType == "Collection")
                questData.HasCollectionItems = questCreature.hasCollectionItems(character) == null ? false : true;

            try
            {
                character.ClientSocket.socket.BeginSend(questData.toXML(character));
            }
            catch {}
        }
        public void VendorOpenWindow(Character character, long CreatureID)
        {
            Map CurrentMap = GetMap(character.MapID, character.Instance);
            Vendor vendor = CurrentMap.getVendor(CreatureID);

            if (vendor == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find vendor";
                return;
            }

            vendor.OpenVendorWindow(character);
        }

        public void InspectCharacter(Character character, long inspectCharGUID)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);

            lock (lockItem.LockObj)
            {
                Map CurrentMap = GetMap(character.MapID, character.Instance);
                MapItem CurrentMapItem = null;
                foreach (MapItem mapitem in CurrentMap.MapItems)
                {
                    if (mapitem.MapX == character.MapX && mapitem.MapY == character.MapY)
                    {
                        CurrentMapItem = mapitem;
                        break;
                    }
                }

                Character inspectChar = null;
                foreach (CreatureBase creatureBase in CurrentMapItem.CreaturesBases)
                {
                    if (creatureBase.CreatureID == inspectCharGUID)
                    {
                        if (creatureBase is Character)
                            inspectChar = (Character)creatureBase;
                        break;
                    }
                }

                if (inspectChar == null)
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Cannot find character";

                    character.AddMessage(message);
                    character.PlaySound("Ding", character.MapX, character.MapY);

                    return;
                }

                string result = "";

                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

                xmldoc.WriteStartElement("inspectdata");
                xmldoc.WriteAttributeString("CreatureID", inspectChar.CreatureID.ToString());
                xmldoc.WriteAttributeString("Name", inspectChar.Name);

                xmldoc.WriteRaw(inspectChar.equipManager.toXML(character));

                xmldoc.WriteStartElement("LeftHand");
                if (inspectChar.LeftHand != null)
                    xmldoc.WriteRaw(inspectChar.LeftHand.toXML(character));
                xmldoc.WriteEndElement();

                xmldoc.WriteStartElement("RightHand");
                if (inspectChar.RightHand != null)
                    xmldoc.WriteRaw(inspectChar.RightHand.toXML(character));
                xmldoc.WriteEndElement();

                xmldoc.WriteEndElement();

                xmldoc.Flush();

                xmldoc.Close();

                stringWriter.Flush();

                result = stringWriter.ToString();

                Message msg = new Message();
                msg.CreatureID = inspectChar.CreatureID;
                msg.Type = "server";
                msg.Text = character.Name + " is inspecting you";

                inspectChar.AddMessage(msg);

                try
                {
                    byte[] byData = System.Text.Encoding.ASCII.GetBytes(result + "\0");
                    character.ClientSocket.socket.BeginSend(result);
                }
                catch { }
            }
        }

        
        public void HasKarma(Character character)
        {
            bool result = character.hateManager.hasKarma();

            try
            {
                character.ClientSocket.socket.BeginSend("<haskarmaresult result=\"" + result.ToString().ToLower() + "\" />");
            }
            catch { }
        }

        public void CanForgive(Character character, long toForgiveCharGUID)
        {
            bool result = false;

            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                foreach (CreatureBase creatureBase in character.currentMapItem.CreaturesBases)
                {
                    if (creatureBase.CreatureID == toForgiveCharGUID)
                    {
                        if (character.hateManager.GetCreatureHateInfo(creatureBase) != null ||
                            creatureBase.hateManager.hasKarmaFrom(character.ID))
                        {
                            result = true;
                        }

                        break;
                    }
                }
            }

            try
            {
                character.ClientSocket.socket.BeginSend("<canforgiveresult creatureid=\"" + toForgiveCharGUID.ToString() + "\" result=\"" + result.ToString().ToLower() + "\" />");
            }
            catch {}
        }
        public void Forgive(Character character, long toForgiveCharGUID)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                foreach (CreatureBase creatureBase in character.currentMapItem.CreaturesBases)
                {
                    if (creatureBase.CreatureID == toForgiveCharGUID)
                    {
                        if (character.hateManager.GetCreatureHateInfo(creatureBase) != null)
                        {
                            character.hateManager.ClearHateInfo(creatureBase);
                            character.AddMapItem(character.currentMapItem);
                        }
                        if (creatureBase.hateManager.hasKarmaFrom(character.ID))
                        {
                            Character charToForgive = (Character)creatureBase;
                            charToForgive.RemoveKarmaFrom(character.ID);
                            charToForgive.UpdateKarma(true);
                        }
                        break;
                    }
                }
            }
        }

        public void TradeMakeRequest(Character requestCharacter, long acceptCharGUID)
        {
            AppHandler2 app = this;

            TradeData tradeData = new TradeData(app);
            tradeData.MakeRequest(requestCharacter, acceptCharGUID);
        }
        public void TradeCancel(Character character, bool isBusy)
        {
            TradeData tradeData = character.tradeData;
            if (tradeData != null)
                tradeData.CancelTrade(character, isBusy);
        }
        public void TradeAccept(Character character)
        {
            TradeData tradeData = character.tradeData;
            if (tradeData != null)
                tradeData.AcceptRequest();
        }
        public void TradeAddItem(Character character, long itemGUID)
        {
            TradeData tradeData = character.tradeData;
            if (tradeData != null)
                tradeData.AddItem(character, itemGUID);
        }
        public void TradeRemoveItem(Character character, long itemGUID)
        {
            TradeData tradeData = character.tradeData;
            if (tradeData != null)
                tradeData.RemoveItem(character, itemGUID);
        }
        public void TradeChangeCoins(Character character, int numCoins)
        {
            TradeData tradeData = character.tradeData;
            if (tradeData != null)
                tradeData.ChangeCoins(character, numCoins);
        }
        public void TradeAcceptOffer(Character character)
        {
            TradeData tradeData = character.tradeData;
            if (tradeData != null)
                tradeData.AcceptTradeOffer(character);
        }
        public void TrainerTrain(Character character, int numCoins, long trainerCreatureID)
        {
            Map CurrentMap = GetMap(character.MapID, character.Instance);
            Trainer trainer = CurrentMap.getTrainer(trainerCreatureID);

            if (trainer == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find trainer";
                
                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);

                return;
            }

            trainer.Train(character, numCoins);
        }
        public void TrainerBuySkill(Character character, int skillDB_ID, long trainerCreatureID)
        {
            Map CurrentMap = GetMap(character.MapID, character.Instance);
            Trainer trainer = CurrentMap.getTrainer(trainerCreatureID);

            if (trainer == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find trainer";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);

                return;
            }

            trainer.BuySkill(character, skillDB_ID);
        }
        public void TrainerBuySpell(Character character, int spellDB_ID, long trainerCreatureID)
        {
            Map CurrentMap = GetMap(character.MapID, character.Instance);
            Trainer trainer = CurrentMap.getTrainer(trainerCreatureID);

            if (trainer == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find trainer";

                character.PlaySound("Ding", character.MapX, character.MapY);
                character.AddMessage(message);

                return;
            }

            trainer.BuySpell(character, spellDB_ID);
        }
        public void VendorBuyVendorItem(Character character, long itemGUID, long vendorCreatureID)
        {
            Map CurrentMap = GetMap(character.MapID, character.Instance);
            Vendor vendor = CurrentMap.getVendor(vendorCreatureID);

            if (vendor == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find vendor";
                return;
            }

            vendor.BuyVendorItem(character, itemGUID);
        }

        public void VendorSellItem(Character character, long itemGUID, long vendorCreatureID)
        {
            Map CurrentMap = GetMap(character.MapID, character.Instance);
            Vendor vendor = CurrentMap.getVendor(vendorCreatureID);

            if (vendor == null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = "server";
                message.Text = "Cannot find vendor";
                return;
            }

            vendor.SellItem(character, itemGUID);
        }


        public void SelfBind(Character character)
        {
            LockItem myLock = GetLockItem(character.MapID, character.Instance);

            lock (myLock.LockObj)
            {
                bool foundBinder = false;
                foreach (MapItem mapItem in character.currentMapItem.mapItemsWithin4)
                {
                    if (Math.Abs(mapItem.MapX - character.MapX) <= 2 && Math.Abs(mapItem.MapY - character.MapY) <= 2)
                    {
                        foreach (CreatureBase creatureBase in mapItem.CreaturesBases)
                        {
                            if (creatureBase.CreatureType == "Binder")
                            {
                                foundBinder = true;
                                break;
                            }
                        }
                    }
                    if (foundBinder == true)
                        break;
                }

                if (foundBinder == true)
                {
                    character.BindMapID = character.MapID;
                    character.BindMapX = character.MapX;
                    character.BindMapY = character.MapY;
                    character.SendMessage("Your spirit is now bound to your current location.", "server");
                }
                else
                {
                    character.SendMessage("No spirit binder nearby.", "server");
                    character.PlaySound("Ding", character.MapX, character.MapY);
                }
            }
        }

        public string Teleport(Character character, int PortalMapID, int PortalMapX, int PortalMapY)
        {
            return Teleport(character, PortalMapID, PortalMapX, PortalMapY, null);
        }
        public string Teleport(Character character, int PortalMapID, int PortalMapX, int PortalMapY, Action preTransferMethod)
        {
            AppHandler2 app = this;

            //Get Lock
            LockItem MyLock = GetLockItem(character.MapID, character.Instance);

            List<MapItem> MapItemsToUpdate = new List<MapItem>();

            lock (MyLock.LockObj)
            {
                //Cant teleport with pets.
                if (character.petManager != null)
                    character.petManager.DismissPet(-1);

                List<Character> CharsToUpdate = new List<Character>();
                foreach (MapItem mapitem in character.currentMapItem.mapItemsWithin8)
                {
                    foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                    {
                        if (creatureBase is Character)
                        {
                            Character character1 = (Character)creatureBase;
                            if (character1.ID != character.ID)
                                CharsToUpdate.Add(character1);
                        }
                    }
                }

                //If this server does not own the map we're moving to, end this function and wait
                //For the response from primary server to move the character
                if (Managers.localWorldsManager.ownsWorld(PortalMapID, character.Instance) == false)
                {
                    //Make transfer character request
                    TransferCharacterRequestWS transferRequest = new TransferCharacterRequestWS();
                    transferRequest.character = character;
                    transferRequest.MapID = PortalMapID;
                    transferRequest.Instance = character.Instance;
                    transferRequest.MapX = PortalMapX;
                    transferRequest.MapY = PortalMapY;

                    //Default behavior, Teleport does not set busy, transfering to another server un-busys, so we need to one before the transfer
                    if (preTransferMethod == null)
                        transferRequest.preTransferMethod = character.addBusyCounter;
                    else
                        transferRequest.preTransferMethod = preTransferMethod;

                    //TODO: Add portal sound
                    transferRequest.PortalSound = "";

                    //If send to primary fails
                    if (Managers.transferCharacterManager.SendTransferRequest(transferRequest) == false)
                    {
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return "Map is currently unavailable";
                    }

                    return "";
                }

                if (character.currentMapItem != null)
                {
                    character.currentMapItem.CreaturesBases.Remove(character);
                    MapItemsToUpdate.Add(character.currentMapItem);
                }

                //Send MapItem Updates to Nearby Characters
                foreach (Character character2 in CharsToUpdate)
                {
                    character2.AddMapItems(MapItemsToUpdate, false);
                }

                //Set this before the lock ends. Any other methods that are waiting for this lock to open for this character
                //Will be stopped and re-invoked when this is set to back to false.
                character.setIsChangingMaps(true);    
           
            }//END LOCK 1

            character.MapID = PortalMapID;

            //Get Lock 2
            LockItem MyLock2 = GetLockItem(PortalMapID, character.Instance);

            List<Character> CharsToUpdate2 = new List<Character>();
            List<MapItem> MapItemsToUpdate2 = new List<MapItem>();
            List<MapItem> MyMapItems = new List<MapItem>();

            lock (MyLock2.LockObj)
            {
                //Get Map
                Map MyMap = GetMap(PortalMapID, character.Instance);

                foreach (MapItem mapitem in MyMap.MapItems)
                {
                    if (mapitem.MapX == PortalMapX && mapitem.MapY == PortalMapY)
                    {
                        character.SetPosition(mapitem);
                        mapitem.CreaturesBases.Add(character);
                        MapItemsToUpdate2.Add(mapitem);
                    }
                    if ((mapitem.MapX >= PortalMapX - 8 && mapitem.MapX <= PortalMapX + 8) && (mapitem.MapY >= PortalMapY - 8 && mapitem.MapY <= PortalMapY + 8))
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character character3 = (Character)creatureBase;
                                if (character3.ID != character.ID)
                                    CharsToUpdate2.Add(character3);
                            }
                        }
                        MyMapItems.Add(mapitem);
                    }
                }
                foreach (Character character3 in CharsToUpdate2)
                {
                    character3.AddMapItems(MapItemsToUpdate2, false);
                }
                character.Update_Character();
                character.AddMapItems(MyMapItems, true);
                MyMap.LootMngr.GetLootInArea(character);

                //Release the map transfer. This will invoke any other methods that got stopped due to the map transfer.
                character.setIsChangingMaps(false);

            }//END LOCK 2

            return "true";
        }
        public string UsePortal(Character character, int MapX, int MapY)
        {
            AppHandler2 app = this;

            //Get Lock
            LockItem MyLock = GetLockItem(character.MapID, character.Instance);
            
            List<MapItem> MapItemsToUpdate = new List<MapItem>();

            int PortalMapID = -1;
            int PortalMapX = -1;
            int PortalMapY = -1;
            lock (MyLock.LockObj)
            {
                if (character.HP < 1)
                {
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    return "You cannot use a portal while dead!";
                }

                List<Character> CharsToUpdate = new List<Character>();
                foreach (MapItem mapitem in character.currentMapItem.mapItemsWithin8)
                {
                    if (mapitem.MapX == MapX && mapitem.MapY == MapY)
                    {
                        if (mapitem.TerrainType != "Portal" && mapitem.TerrainType != "StairsUp" &&
                            mapitem.TerrainType != "StairsDown" && mapitem.TerrainType != "RopeUp" && mapitem.TerrainType != "RopeDown")
                            return "Cannot find portal.";

                        if (Math.Abs(character.MapX - mapitem.MapX) > 0 || Math.Abs(character.MapY - mapitem.MapY) > 0)
                        {
                            if (mapitem.TerrainType == "Portal" || mapitem.TerrainType == "StairsUp" || mapitem.TerrainType == "StairsDown")
                                return "You are to far away from the portal";
                            if (Math.Abs(character.MapX - mapitem.MapX) > 1 || Math.Abs(character.MapY - mapitem.MapY) > 1)
                                return "You are to far away from the portal";
                        }

                        if (mapitem.MeetsPortalRequirements(character) == false)
                        {
                            character.PlaySound("Ding", character.MapX, character.MapY);
                            return "This portal requires " + mapitem.PortalSkillType + " skill of at least " + mapitem.PortalLevelRequirement.ToString();
                        }

                        PortalMapID = mapitem.PortalMapID;
                        PortalMapX = mapitem.PortalX;
                        PortalMapY = mapitem.PortalY;

                        if (mapitem.TerrainType == "StairsUp")
                        {
                            //SoundObj = new Object[] { "DoorOpen", 4, mapitem.MapX, mapitem.MapY };
                            //Sounds.Add(SoundObj);
                        }
                        else if (mapitem.TerrainType == "StairsDown")
                        {
                            //SoundObj = new Object[] { "DoorOpen", 4, mapitem.MapX, mapitem.MapY };
                            //Sounds.Add(SoundObj);
                        }
                        else if (mapitem.TerrainType == "Portal")
                        {
                            //SoundObj = new Object[] { "DoorOpen", 4, mapitem.MapX, mapitem.MapY };
                            //Sounds.Add(SoundObj);
                        }
                    }
                    if ((mapitem.MapX >= MapX - 8 && mapitem.MapX <= MapX + 8) && (mapitem.MapY >= MapY - 8 && mapitem.MapY <= MapY + 8))
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character character1 = (Character)creatureBase;
                                if (character1.ID != character.ID)
                                    CharsToUpdate.Add(character1);
                            }
                        }
                    }
                }

                //If this server does not own the map we're moving to, end this function and wait
                //For the response from primary server to move the character
                if (Managers.localWorldsManager.ownsWorld(PortalMapID, character.Instance) == false)
                {
                    //Make transfer character request
                    TransferCharacterRequestWS transferRequest = new TransferCharacterRequestWS();
                    transferRequest.character = character;
                    transferRequest.MapID = PortalMapID;
                    transferRequest.Instance = character.Instance;
                    transferRequest.MapX = PortalMapX;
                    transferRequest.MapY = PortalMapY;
                    
                    //TODO: Add portal sound
                    transferRequest.PortalSound = "";

                    //If send to primary fails
                    if (Managers.transferCharacterManager.SendTransferRequest(transferRequest) == false)
                    {
                        character.PlaySound("Ding", character.MapX, character.MapY);
                        return "Map is currently unavailable";
                    }

                    return "";
                }

                character.currentMapItem.CreaturesBases.Remove(character);
                MapItemsToUpdate.Add(character.currentMapItem);

                //Send MapItem Updates to Nearby Characters
                foreach (Character character2 in CharsToUpdate)
                {
                    character2.AddMapItems(MapItemsToUpdate, false);
                }

                //Set this before the lock ends. Any other methods that are waiting for this lock to open for this character
                //Will be stopped and re-invoked when this is set to back to false.
                character.setIsChangingMaps(true);  

            }//END LOCK 1

            character.MapID = PortalMapID;

            //Get Lock 2
            LockItem MyLock2 = GetLockItem(PortalMapID, character.Instance);

            List<Character> CharsToUpdate2 = new List<Character>();
            List<MapItem> MapItemsToUpdate2 = new List<MapItem>();
            List<MapItem> MyMapItems = new List<MapItem>();

            lock (MyLock2.LockObj)
            {
                //Get Map
                Map MyMap = GetMap(PortalMapID, character.Instance);
                
                foreach (MapItem mapitem in MyMap.MapItems)
                {
                    if (mapitem.MapX == PortalMapX && mapitem.MapY == PortalMapY)
                    {
                        //Pets only follow up and down stairs, so if we used a different type of portal, dismiss the pets
                        if (mapitem.TerrainType != "StairsUp" && mapitem.TerrainType != "StairsDown")
                        {
                            if (character.petManager != null)
                                character.petManager.DismissPet(-1);
                        }

                        character.SetPosition(mapitem);

                        mapitem.CreaturesBases.Add(character);
                        MapItemsToUpdate2.Add(mapitem);
                    }
                    if ((mapitem.MapX >= PortalMapX - 8 && mapitem.MapX <= PortalMapX + 8) && (mapitem.MapY >= PortalMapY - 8 && mapitem.MapY <= PortalMapY + 8))
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character character3 = (Character)creatureBase;
                                if (character3.ID != character.ID)
                                    CharsToUpdate2.Add(character3);
                            }
                        }
                        MyMapItems.Add(mapitem);
                    }
                }

                foreach (Character character3 in CharsToUpdate2)
                    character3.AddMapItems(MapItemsToUpdate2, false);

                character.Update_Character();
                character.AddMapItems(MyMapItems, true);
                MyMap.LootMngr.GetLootInArea(character);

                //Release the map transfer. This will invoke any other methods that got stopped due to the map transfer.
                character.setIsChangingMaps(false);

            }//END LOCK 2
            character.Timer_Round_Interval = System.Convert.ToDouble(character.MovementSpeed * 1000);
            character.Timer_Round_Start();
            return "true";
        }

        public string RangeAttack(Character MyCharacter, long CreatureID, long ItemGUID)
        {
            Weapon weapon = null;

            LockItem MyLock = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);
            lock (MyLock.LockObj)
            {

                if (CreatureID == MyCharacter.CreatureID)
                {
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    return "You cannot attack yourself!";
                }

                bool useExtendedReach = false; //(1 tile range melee attack)

                //1 handed range item, can throw from anywhere, hand, belt & does not require a free hand
                //Find the weapon
            
                //Check left hand
                Loot leftHandItem = MyCharacter.LeftHand;
                if (leftHandItem != null && leftHandItem is Weapon && leftHandItem.GameUID == ItemGUID)
                {
                    weapon = (Weapon)leftHandItem;
                    if (weapon.Range != true)
                        return "Weapon is not a range weapon";
                }

                //Check right hand
                Loot rightHandItem = MyCharacter.RightHand;
                if (rightHandItem != null && rightHandItem is Weapon && rightHandItem.GameUID == ItemGUID)
                {
                    weapon = (Weapon)rightHandItem;
                    if (weapon.Range == false)
                    {
                        if (MyCharacter.weaponSkillManager.hasExtendedReach(weapon) == false)
                            return "Weapon is not a range weapon";
                        else
                            useExtendedReach = true;
                    }
                    else if (weapon.Slot != "RightHand" && weapon.Slot != "EitherHand" && weapon.Slot != "2Hand")
                    {
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        return "You cannot use that weapon from your right hand";
                    }
                }

                //Check belt
                if (weapon == null)
                {
                    Loot beltItem = MyCharacter.beltManager.GetBeltItem(ItemGUID);
                    if (beltItem != null && beltItem is Weapon)
                    {
                        weapon = (Weapon)beltItem;
                        if (weapon.Range != true)
                            return "Weapon is not a range weapon";
                    }
                }
            
                //Check bag
                if (weapon == null)
                {
                    Loot bagItem = MyCharacter.bagManager.getBagItem(ItemGUID);
                    if (bagItem != null && bagItem is Weapon)
                    {
                        weapon = (Weapon)bagItem;
                        if (weapon.Range != true)
                            return "Weapon is not a range weapon";
                    }
                }

                if (weapon == null)
                    return "Cannot find weapon";

                int maxRange = 4;
                if (useExtendedReach)
                    maxRange = 1;

                 // 2 Handed range item (must be in right hand and left hand must be free)
                if (weapon.Slot == "2Hand") 
                {
                    Loot lHandItem = MyCharacter.LeftHand;
                    Loot rHandItem = MyCharacter.RightHand;
                    if (lHandItem != null || rHandItem == null || rHandItem.GameUID != ItemGUID)
                    {
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        return "2 Handed weapons must be used from the right hand, with left hand free";
                    }
                }

                if (MyCharacter.equipManager.MeetsRequirements(weapon) == false)
                {
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    return "You do not meet the requirements to use this weapon";
                }

            
                //MapItem CreatureMapItem = null;
                List<Character> CharactersWithin12 = new List<Character>();
                List<Character> CharactersWithin4 = new List<Character>();
                //List<MapItem> MapItemsWithin4 = new List<MapItem>();

                //Find the creature we're attacking
                CreatureBase CreatureToAttack = null;
                foreach (MapItem mapitem in MyCharacter.currentMapItem.mapItemsWithin12)
                {
                    if (Math.Abs(mapitem.MapX - MyCharacter.MapX) <= 4 && Math.Abs(mapitem.MapY - MyCharacter.MapY) <= 4)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            //TODO: Validate that the creatures tile is not hidden (shouldnt happen unless someone is hacking)
                            if (creatureBase.CreatureID == CreatureID && 
                                creatureBase.HP > 0 && 
                                Math.Abs(creatureBase.MapX - MyCharacter.MapX) <= maxRange && 
                                Math.Abs(creatureBase.MapY - MyCharacter.MapY) <= maxRange)
                            {
                                CreatureToAttack = creatureBase;
                            }

                            if (creatureBase is Character)
                                CharactersWithin4.Add((Character)creatureBase);
                        }
                    }
                    foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                    {
                        if (creatureBase is Character)
                            CharactersWithin12.Add((Character)creatureBase);
                    }
                }
                if (CreatureToAttack == null)
                {
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    return "Creature is to far away";
                }

                int AtkDelay;
                //-1 for miss

                int attackDamage = MyCharacter.AttackCreatureBase(CreatureToAttack, weapon, !useExtendedReach, false, false, out AtkDelay);

                if (AtkDelay == -1)
                {
                    MyCharacter.SetBusy(false);
                    return "true";
                }

                if (attackDamage > 0)
                {
                    CreatureToAttack.Update_Character();

                    if (CreatureToAttack.HP < 1)
                    {
                        if (!(CreatureToAttack is Character))
                        {
                            CreatureToAttack.currentMapItem.CreaturesBases.Remove(CreatureToAttack);
                        }
                        foreach (Character character in CharactersWithin12)
                        {
                            if (Math.Abs(character.MapX - CreatureToAttack.MapX) <= 4 && Math.Abs(character.MapY - CreatureToAttack.MapY) <= 4)
                            {
                                character.AddMapItem(CreatureToAttack.currentMapItem);
                            }
                        }
                    }
                    else
                    {
                        foreach (Character character in CharactersWithin12)
                        {
                            if (Math.Abs(character.MapX - CreatureToAttack.MapX) <= 4 && Math.Abs(character.MapY - CreatureToAttack.MapY) <= 4)
                                character.UpdateCreatureBaseHp(CreatureToAttack);
                        }
                    }
                }
                
                
                //Move weapon
                if (weapon.RangeThrows == true)
                {
                    bool dropItem = true;

                    //Remove the item from the bag or the belt.
                    if (MyCharacter.beltManager.RemoveBeltItem(weapon.GameUID) != null)
                        MyCharacter.beltManager.UpdateBelt();
                    if (MyCharacter.bagManager.removeBagItem(weapon.GameUID) != null)
                        MyCharacter.bagManager.UpdateBag();

                    //Check if its in left hand
                    if (MyCharacter.LeftHand != null && MyCharacter.LeftHand.GameUID == ItemGUID)
                    {
                        //Only move it if its not a returning weapon or they missed
                        if (weapon.ThrowReturns == false || attackDamage == -1)
                        {
                            MyCharacter.LeftHand = null;
                            MyCharacter.Update_Character();
                        }
                        //Flag to not drop the item on the ground
                        else
                            dropItem = false;
                    }
                    if (MyCharacter.RightHand != null && MyCharacter.RightHand.GameUID == ItemGUID)
                    {
                        //Only move it if its not a returning weapon or they missed
                        if (weapon.ThrowReturns == false || attackDamage == -1)
                        {
                            MyCharacter.RightHand = null;
                            MyCharacter.Update_Character();
                        }
                        else
                            dropItem = false;
                    }

                    //The item was not in our hand when we threw it. Try to place it into the hand as long as we didnt miss
                    if (dropItem == true && attackDamage != -1 && weapon.ThrowReturns == true)
                    {
                        if (MyCharacter.RightHand == null && (weapon.Slot == "RightHand" || weapon.Slot == "EitherHand"))
                        {
                            MyCharacter.RightHand = weapon;
                            MyCharacter.Update_Character();
                            dropItem = false;
                        }
                        else if (MyCharacter.LeftHand == null && (weapon.Slot == "LeftHand" || weapon.Slot == "EitherHand"))
                        {
                            MyCharacter.LeftHand = weapon;
                            MyCharacter.Update_Character();
                            dropItem = false;
                        }
                    }

                    if (dropItem)
                    {
                        List<Loot> ItemsToDrop = new List<Loot>();
                        ItemsToDrop.Add(weapon);

                        Map CurrentMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);
                        CurrentMap.LootMngr.DropItems(CreatureToAttack.MapX, CreatureToAttack.MapY, ItemsToDrop, true);
                    }

                    //Update Creature base to update hands on crit list.
                    foreach (Character charToUpdate in CharactersWithin4)
                        charToUpdate.AddCreatureBase(MyCharacter);
                }

                MyCharacter.Timer_Round_Interval = AtkDelay;
                MyCharacter.Timer_Round_Start();
            }

            return "true";
        }

        public void AttackCreature(Character myCharacter, long CreatureID)
        {
            if (CreatureID == myCharacter.CreatureID)
            {
                Message message = new Message();
                message.CreatureID = myCharacter.CreatureID;
                message.Type = "server";
                message.Text = "You cannot attack yourself";

                myCharacter.AddMessage(message);
                myCharacter.SetBusy(false);
                myCharacter.PlaySound("Ding", myCharacter.MapX, myCharacter.MapY);
                return;
            }

            LockItem MyLock = GetLockItem(myCharacter.MapID, myCharacter.Instance);
            CreatureBase CritToAttackMap = null;

            lock (MyLock.LockObj)
            {
                List<Character> CharactersWithin12 = new List<Character>();
                foreach (MapItem mapitem in myCharacter.currentMapItem.mapItemsWithin12)
                {
                    if (mapitem.MapX == myCharacter.MapX && mapitem.MapY == myCharacter.MapY)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase.CreatureID == CreatureID && creatureBase.HP > 0)
                                CritToAttackMap = creatureBase;
                        }
                        if (CritToAttackMap == null)
                        {
                            Message message = new Message();
                            message.CreatureID = myCharacter.CreatureID;
                            message.Type = "server";
                            message.Text = "Cannot find creature";

                            myCharacter.AddMessage(message);
                            myCharacter.PlaySound("Ding", myCharacter.MapX, myCharacter.MapY);
                            myCharacter.SetBusy(false);
                            return;
                        }
                    }

                    if (Math.Abs(mapitem.MapX - myCharacter.MapX) <= 12 && Math.Abs(mapitem.MapY - myCharacter.MapY) <= 12)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character character = (Character)creatureBase;
                                CharactersWithin12.Add(character);
                            }
                        }
                    }
                }

                int Delay;
                if (myCharacter.AttackCreatureBase(CritToAttackMap, false, out Delay) > 0)
                {
                    CritToAttackMap.Update_Character();

                    if (CritToAttackMap.HP < 1)
                    {
                        if (!(CritToAttackMap is Character))
                        {
                            myCharacter.currentMapItem.CreaturesBases.Remove(CritToAttackMap);
                        }
                        foreach (Character character in CharactersWithin12)
                        {
                            if (Math.Abs(character.MapX - CritToAttackMap.MapX) <= 4 && Math.Abs(character.MapY - CritToAttackMap.MapY) <= 4)
                            {
                                character.AddMapItem(myCharacter.currentMapItem);
                            }
                        }
                    }
                    else
                    {
                        foreach (Character character in CharactersWithin12)
                        {
                            if (Math.Abs(character.MapX - CritToAttackMap.MapX) <= 4 && Math.Abs(character.MapY - CritToAttackMap.MapY) <= 4)
                                character.UpdateCreatureBaseHp(CritToAttackMap);
                        }
                    }
                }

                myCharacter.Timer_Round_Interval = Delay;
                myCharacter.Timer_Round_Start();
            }
        }

        public string MoveItem(Character MyCharacter, long ItemGUID, string ItemSource, int ItemSourceX, int ItemSourceY,
                                string ItemDestination, int ItemDestinationX, int ItemDestinationY, int pageNumber)
        {
            //Move logic:
            //1 Get copy of item and see if requirements are met to move the item
            //2 Check if destination is available
            //3 Attempt to remove item
            //4 Add item to destination

            LockItem lockItem = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);
            lock (lockItem.LockObj) 
            {

                //We did not locate the item
                if (MyCharacter.HP < 1)
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "You cant do that while dead!";
                    MyCharacter.AddMessage(message);

                    return "false";
                }

                AppHandler2 app = this;
                Map CurrentMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);

                bool updateCreatureBase = false;
                bool updateEquipment = false;
                bool updateBelt = false;
                bool updateBag = false;

                int Delay = 1100;

                Loot ItemToMove = null;

                //Get copy of item to see if character meets requirements to move
                if (ItemSource == "Bag")
                    ItemToMove = MyCharacter.bagManager.getBagItem(ItemGUID);

                else if (ItemSource == "Belt")
                    ItemToMove = MyCharacter.beltManager.GetBeltItem(ItemGUID);

                else if (ItemSource == "Left")
                    ItemToMove = MyCharacter.LeftHand;

                else if (ItemSource == "Right")
                    ItemToMove = MyCharacter.RightHand;

                else if (MyCharacter.equipManager.isValidSlot(ItemSource))
                    ItemToMove = MyCharacter.equipManager.GetEquipment(ItemSource);

                else if (ItemSource == "Ground")
                    ItemToMove = CurrentMap.LootMngr.GetItem(ItemSourceX, ItemSourceY, ItemGUID);

                //We did not locate the item
                if (ItemToMove == null)
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "Cannot find item";
                    MyCharacter.AddMessage(message);

                    return "false";
                }

                if (ItemSource == "Ground" && ItemToMove.Lore == true && MyCharacter.hasItem(ItemToMove.ID))
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "You cannot carry any more of those items.";
                    MyCharacter.AddMessage(message);

                    return "false";
                }

                IConsumable consumableObject = null;
                if (ItemDestination == "Consume" && ItemToMove.CanConsume)
                {
                    Assembly assembly = Assembly.GetExecutingAssembly();
                    string fullTypeName = "Reborn_Server.App1AppHandler" + "." + ItemToMove.ClassName;
                    Type myType = assembly.GetType(fullTypeName);

                    consumableObject = (IConsumable)Activator.CreateInstance(myType);
                    if (consumableObject.MeetsConsumeRequirements(MyCharacter, ItemToMove) == false)
                    {
                        MyCharacter.SetBusy(false);
                        return "false";
                    }
                }

                //Check if destination is equipment
                if (MyCharacter.equipManager.isValidSlot(ItemDestination))
                {
                    //Destination is equipment but the item we found is not
                    if (!(ItemToMove is Equipment))
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Invalid slot";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }

                    Equipment equipment = (Equipment)ItemToMove;

                    //Make sure the item fits into the requested equipment slot (Destination "WristLeft" = ItemSlot "Wrist")
                    if (ItemDestination.IndexOf(equipment.Slot) == -1)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Invalid slot";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }

                    if (MyCharacter.equipManager.MeetsRequirements(equipment) == false)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "You do not meet the requirements to equip this item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if ((ItemDestination == "Bag" && ItemToMove.Bag == false) ||
                    (ItemDestination == "Belt" && ItemToMove.Belt == false) ||
                    (ItemDestination == "Consume" && ItemToMove.CanConsume == false))
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "Invalid Destination Position";
                    MyCharacter.AddMessage(message);

                    return "false";
                }


                //Step 2: Check if the destination is available before we remove the item to move
                if (ItemDestination == "Bag")
                {
                    if (MyCharacter.bagManager.getBagItem(pageNumber, ItemDestinationX) != null)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Position not available";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemDestination == "Belt")
                {
                    if (MyCharacter.beltManager.GetBeltItem(ItemDestinationX) != null)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Position not available";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemDestination == "Left")
                {
                    if (MyCharacter.LeftHand != null)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Position not available";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemDestination == "Right")
                {
                    if (MyCharacter.RightHand != null)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Position not available";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (MyCharacter.equipManager.isValidSlot(ItemDestination))
                {
                    if (MyCharacter.equipManager.GetEquipment(ItemDestination) != null)
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Position not available";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                //Should never get here
                else if (ItemDestination != "Consume" && ItemDestination != "Ground")
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "Invalid destination position";
                    MyCharacter.AddMessage(message);

                    return "false";
                }


                //Step 3: Destination must be valid and available, try to take the item
                if (ItemSource == "Bag")
                {
                    ItemToMove = MyCharacter.bagManager.removeBagItem(ItemGUID);
                    if (ItemToMove != null)
                        updateBag = true;
                    else
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Cannot find item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemSource == "Belt")
                {
                    ItemToMove = MyCharacter.beltManager.RemoveBeltItem(ItemGUID);
                    if (ItemToMove != null)
                        updateBelt = true;
                    else
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Cannot find item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemSource == "Left")
                {
                    ItemToMove = MyCharacter.LeftHand;
                    if (ItemToMove != null)
                    {
                        updateCreatureBase = true;
                        MyCharacter.LeftHand = null;
                    }
                    else
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Cannot find item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemSource == "Right")
                {
                    ItemToMove = MyCharacter.RightHand;
                    if (ItemToMove != null)
                    {
                        updateCreatureBase = true;
                        MyCharacter.RightHand = null;
                    }
                    else
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Cannot find item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (MyCharacter.equipManager.isValidSlot(ItemSource))
                {
                    ItemToMove = MyCharacter.equipManager.RemoveEquipment(ItemSource);
                    if (ItemToMove != null)
                        updateEquipment = true;
                    else
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Cannot find item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                else if (ItemSource == "Ground")
                {
                    ItemToMove = CurrentMap.LootMngr.TakeItem(ItemSourceX, ItemSourceY, ItemGUID);
                    if (ItemToMove != null)
                    {
                        //Bind the item if it is bind on pick up
                        if (ItemToMove.BoundTo < -1)
                            ItemToMove.BoundTo = MyCharacter.ID;

                        //Set the carrier character if its a CorpseCharacter
                        if (ItemToMove is CorpseCharacter)
                        {
                            CorpseCharacter corpseChar = (CorpseCharacter)ItemToMove;
                            corpseChar.CarrierCharacter = MyCharacter;
                        }
                    }
                    else
                    {
                        MyCharacter.SetBusy(false);
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        Message message = new Message();
                        message.Type = "server";
                        message.CreatureID = MyCharacter.CreatureID;
                        message.Text = "Cannot find item";
                        MyCharacter.AddMessage(message);

                        return "false";
                    }
                }
                //Should not get here
                else
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "Invalid Source Position";
                    MyCharacter.AddMessage(message);

                    return "false";
                }

                if (ItemToMove == null)
                {
                    MyCharacter.SetBusy(false);
                    MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                    Message message = new Message();
                    message.Type = "server";
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Text = "Can not find item";
                    MyCharacter.AddMessage(message);

                    return "false";
                }

                //Place the item
                if (ItemDestination == "Bag")
                {
                    MyCharacter.bagManager.addBagItem(pageNumber, ItemDestinationX, ItemToMove);
                    updateBag = true;
                }
                else if (ItemDestination == "Belt")
                {
                    MyCharacter.beltManager.AddItem(ItemToMove, ItemDestinationX);
                    updateBelt = true;
                }
                else if (ItemDestination == "Left")
                {
                    MyCharacter.LeftHand = ItemToMove;
                    updateCreatureBase = true;
                }
                else if (ItemDestination == "Right")
                {
                    MyCharacter.RightHand = ItemToMove;
                    updateCreatureBase = true;
                }
                else if (MyCharacter.equipManager.isValidSlot(ItemDestination))
                {
                    Equipment equip = (Equipment)ItemToMove;
                    MyCharacter.equipManager.AddEquipment(equip, ItemDestination);
                    updateEquipment = true;
                }
                else if (ItemDestination == "Ground")
                {
                    List<Loot> ItemsToDrop = new List<Loot>();
                    ItemsToDrop.Add(ItemToMove);
                    CurrentMap.LootMngr.DropItems(ItemDestinationX, ItemDestinationY, ItemsToDrop, true);

                    //Remove the carrier character if CorpseCharacter
                    if (ItemToMove is CorpseCharacter)
                    {
                        CorpseCharacter corpseChar = (CorpseCharacter)ItemToMove;
                        corpseChar.CarrierCharacter = null;
                    }
                }
                else if (ItemDestination == "Consume")
                {
                    Delay = 3000;

                    //Async this, the consume might lock a different map (like teleport potion resultint in potential deadlock)
                    Action<Character, Loot> consumeMethod = (Action<Character, Loot>)consumableObject.Consume;
                    consumeMethod.BeginInvoke(MyCharacter, ItemToMove, null, null);

                    updateCreatureBase = true;
                }

                MyCharacter.updateWeight();
                MyCharacter.Timer_Round_Interval = Delay;
                MyCharacter.Timer_Round_Start();

                if (updateEquipment == true)
                {
                    MyCharacter.Update_Character();
                    MyCharacter.UpdateEquipment();
                }
                if (updateCreatureBase == true)
                {
                    MyCharacter.Update_Character();

                    foreach (Map map in Maps)
                    {
                        if (map.MapID == MyCharacter.MapID && map.MapInstance == MyCharacter.Instance)
                        {
                            foreach (MapItem mapitem in map.MapItems)
                            {
                                if (mapitem.MapX - MyCharacter.MapX >= -4 && mapitem.MapX - MyCharacter.MapX <= 4 &&
                                    mapitem.MapY - MyCharacter.MapY >= -4 && mapitem.MapY - MyCharacter.MapY <= 4)
                                {
                                    lock (mapitem)
                                    {
                                        foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                                        {
                                            if (creaturebase is Character)
                                            {
                                                Character character = (Character)creaturebase;
                                                character.AddCreatureBase(MyCharacter);
                                            }
                                        }
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
                if (updateBelt == true)
                    MyCharacter.beltManager.UpdateBelt(); 
                if (updateBag == true)
                    MyCharacter.bagManager.UpdateBag();

                //Items removed from the ground will already be removed from the clients drag, do not send the result.
                if (ItemSource == "Ground")
                    return "noResult";
                else
                    return "<moveitem_result itemGuid=\"" + ItemToMove.GameUID.ToString() + "\">true</moveitem_result>";
            }
        }

        public string MoveSpell(Character character, int sourcePageNumber, int sourceIndex, int destPageNumber, int destIndex)
        {
            if (character.spellManager.moveSpellIcon(sourcePageNumber, sourceIndex, destPageNumber, destIndex) == true)
            {
                character.Timer_Round_Interval = 1100;
                character.Timer_Round_Start();

                return "true";
            }
            else
                return "Error moving spell";
        }

        public void Resurrect(Character character)
        {
            character.Timer_Respawn.Stop();

            if (Managers.localWorldsManager.ownsWorld(character.BindMapID, character.Instance))
                Resurrect(character, character.BindMapID, character.BindMapX, character.BindMapY, 100, true);
            else
            {
                //Make transfer character request
                TransferCharacterRequestWS transferRequest = new TransferCharacterRequestWS();
                transferRequest.character = character;
                transferRequest.MapID = character.BindMapID;
                transferRequest.Instance = character.Instance;
                transferRequest.MapX = character.BindMapX;
                transferRequest.MapY = character.BindMapY;

                //TODO: Add portal sound
                transferRequest.PortalSound = "";

                transferRequest.customErrorHandler = character.ressurectionFailureHandler;
                transferRequest.preTransferMethod = character.ressurectionPreTransfer;

                //If send to primary fails, rez at maps starting position (probably to be replaced with last portal)
                if (Managers.transferCharacterManager.SendTransferRequest(transferRequest) == false)
                {
                    Resurrect(character, -1, -1, -1, 100, true);
                }
            }
        }

        //Only handles ressurections that are local to this server.
        public void Resurrect(Character MyCharacter, int MapID, int MapX, int MapY, int percentExpPenalty, bool moveCharacter)
        {
            MyCharacter.Timer_Respawn.Stop();

            //Cant remember why this is here... but if there is no ID dont resurrect.
            if (MyCharacter.ID == -1)
                return;

            AppHandler2 app = this;

            //GET LOCK
            LockItem lockitem = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);
            //GET MAP
            Map CurrentMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);

            //REMOVE CHARACTER & CORPSE FROM MAP
            lock (lockitem.LockObj)
            {
                if (MyCharacter.HP > 0)
                    return;

                if (MyCharacter.myCorpse != null)
                {
                    if (MyCharacter.myCorpse.CarrierCharacter != null)
                    {
                        if (MyCharacter.myCorpse.CarrierCharacter.LeftHand == MyCharacter.myCorpse)
                        {
                            MyCharacter.myCorpse.CarrierCharacter.LeftHand = null;
                            MyCharacter.myCorpse.CarrierCharacter.Update_Character();
                        }
                        else if (MyCharacter.myCorpse.CarrierCharacter.RightHand == MyCharacter.myCorpse)
                        {
                            MyCharacter.myCorpse.CarrierCharacter.RightHand = null;
                            MyCharacter.myCorpse.CarrierCharacter.Update_Character();
                        }
                    }
                    else
                        CurrentMap.LootMngr.TakeItem(MyCharacter.myCorpse.MapX, MyCharacter.myCorpse.MapY, MyCharacter.myCorpse.GameUID);

                }
                MyCharacter.myCorpse = null;

                if (moveCharacter)
                {
                    List<MapItem> MapItemsToUpdate = new List<MapItem>();
                    List<Character> CharsToUpdate = new List<Character>();
                    foreach (MapItem mapitem in MyCharacter.currentMapItem.mapItemsWithin4)
                    {
                        if (mapitem.MapX == MyCharacter.MapX && mapitem.MapY == MyCharacter.MapY)
                        {
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase == MyCharacter)
                                {
                                    mapitem.CreaturesBases.Remove(MyCharacter);
                                    MapItemsToUpdate.Add(mapitem);
                                    break;
                                }
                            }
                        }
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character cbChar = (Character)creatureBase;
                                CharsToUpdate.Add(cbChar);
                            }
                        }
                    }
                    foreach (Character character in CharsToUpdate)
                    {
                        character.AddMapItems(MapItemsToUpdate, false);
                    }
                }
            }//End Lock

            //RESET CHARACTER
            MyCharacter.HP = 100;
            MyCharacter.Mana = 100;
            MyCharacter.Stamina = 100;

            if (moveCharacter)
            {
                //No supplied ressurection point, use the maps start point (this will probably get replaced with the players last portal)
                if (MapX == -1 && MapY == -1 && MapID == -1)
                {
                    MapID = CurrentMap.StartMapID;
                    MapX = CurrentMap.StartMapX;
                    MapY = CurrentMap.StartMapY;
                }

                bool updateLoot = false;
                if (MapID != MyCharacter.MapID || MapX != MyCharacter.MapX || MapY != MyCharacter.MapY)
                    updateLoot = true;

                MyCharacter.MapID = MapID;

                LockItem newLock = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);
                lock (newLock.LockObj)
                {
                    CurrentMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);

                    List<Character> CharsToUpdate = new List<Character>();
                    List<MapItem> MapItemsToUpdate = new List<MapItem>();
                    List<MapItem> MyMapItems = new List<MapItem>();

                    foreach (MapItem mapitem in CurrentMap.MapItems)
                    {
                        if (mapitem.MapX == MapX && mapitem.MapY == MapY)
                        {
                            MyCharacter.SetPosition(mapitem);
                            mapitem.CreaturesBases.Add(MyCharacter);
                            MapItemsToUpdate.Add(mapitem);
                        }
                        if (Math.Abs(mapitem.MapX - MapX) <= 8 && Math.Abs(mapitem.MapY - MapY) <= 8)
                        {
                            MyMapItems.Add(mapitem);
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase is Character)
                                {
                                    Character character = (Character)creatureBase;
                                    if (character.ID != MyCharacter.ID)
                                        CharsToUpdate.Add(character);
                                }
                            }
                        }
                    }
                    MyCharacter.Update_Character();

                    MyCharacter.AddMapItems(MyMapItems, true);
                    MyCharacter.skillManager.applyDeathPenalty(percentExpPenalty);

                    foreach (Character character in CharsToUpdate)
                    {
                        character.AddMapItems(MapItemsToUpdate, false);
                    }

                }// End Lock

                MyCharacter.updateKarmaBuff();

                //Update the surrounding loot
                if (updateLoot)
                    MyCharacter.currentMapItem.parentMap.LootMngr.GetLootInArea(MyCharacter);
            }
        }
        

        public string Corpse_Roll(Character MyCharacter, int MapID, int Instance, int MapX, int MapY, long GameUID)
        {
            AppHandler2 app = this;

            Map CurrentMap = GetMap(MapID, Instance);

            Loot corpseLoot = CurrentMap.LootMngr.TakeItem(MapX, MapY, GameUID);

            ICorpse myCorpse;
            if (corpseLoot == null || !(corpseLoot is ICorpse))
                return "Cannot Find Corpse";
            else
                myCorpse = (ICorpse)corpseLoot;

            List<Loot> LootToDrop = myCorpse.RemoveLoot();
            corpseLoot.GameUID = ItemIDGen.GetUID();

            //We get -1 if the corpse is decaying
            if (MyCharacter != null)
            {
                //The Corpse is not decaying so put it back, its been looted
                LootToDrop.Add(corpseLoot);

                MyCharacter.Timer_Round_Interval = 1100;
                MyCharacter.Timer_Round_Start();
            }

            bool useExtendedGarbageTimer = false;
            if (myCorpse is CorpseCharacter)
                useExtendedGarbageTimer = true;

            if (LootToDrop.Count > 0)
                CurrentMap.LootMngr.DropItems(MapX, MapY, LootToDrop, useExtendedGarbageTimer);

            return "true";
        }

        public string ChangePosition(Character MyCharacter, List<string> MoveList, int CreatureID)
        {
            return ChangePosition(MyCharacter, MoveList, CreatureID, false, false);
        }
        public string ChangePosition(Character MyCharacter, List<string> MoveList, int CreatureID, bool isPortal, bool isPush)
        {
            //MyCharacter - Character to move
            //MoveList - List of directions to move (N, NE, NW)
            //CreatureID - Creature to rush attack (-1 if none)
            //isPortal - If this function leads to a portal (like an air tile), we may need to transfer servers.
            //           If a server transfer is required, after we recieve the confirmation from the primary
            //           this function will get re-invoked with isPortal = TRUE
            //isPush - Indicates something else pushed the character, will not start round timer, take stam, etc

            decimal Delay = 3000;
            LockItem MyLock = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);

            Point NewPosition2 = new Point(); //End Point of Char Move
            int NewMapID = MyCharacter.MapID;  //End MapID of Char Move

            CreatureBase CritToAttack = null; //Used for Rush Attack

            //Lock Map
            lock (MyLock.LockObj)
            {
                //Ignore errors is character is being pushed by something
                if (isPush == false)
                {
                    if (MyCharacter.HP < 1)
                    {
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        MyCharacter.SendMessage("You cannot move while dead", "server");
                        MyCharacter.SetBusy(false);

                        return "true";
                    }

                    if (MyCharacter.buffManager.IsStunned() == true)
                    {
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        MyCharacter.SendMessage("You cannot move while stunned!", "server");
                        MyCharacter.SetBusy(false);

                        return "true";
                    }

                    string rootMsg = MyCharacter.buffManager.IsRooted();
                    if (rootMsg != "")
                    {
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        MyCharacter.SendMessage(rootMsg, "server");
                        MyCharacter.SetBusy(false);

                        return "true";
                    }
                }

                //Dont mess with stam if this function is being re-invoked after a successfull server transfer request, or the character is being pushed by something
                if (isPortal == false && isPush == false && MyCharacter.get0verweightBy() > 0 && MoveList.Count > 1)
                {
                    int stamCost = 0;

                    if (MoveList.Count == 4)
                        stamCost = System.Convert.ToInt32(MyCharacter.get0verweightBy());
                    else if (MoveList.Count == 3)
                        stamCost = System.Convert.ToInt32(System.Convert.ToInt32(MyCharacter.get0verweightBy()) * .6);
                    else if (MoveList.Count == 2)
                        stamCost = System.Convert.ToInt32(System.Convert.ToInt32(MyCharacter.get0verweightBy()) * .3);

                    if (MyCharacter.Stamina < stamCost)
                    {
                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        MyCharacter.SendMessage("You do not have enough stamina!", "server");
                        MyCharacter.SetBusy(false);

                        return "true";
                    }
                }

                //Calculate Moves to Map Locations
                Delay = System.Convert.ToDecimal(MyCharacter.MovementSpeed) * 1000;

                List<Point> Positions = new List<Point>();
                Positions.Add(new Point(MyCharacter.MapX, MyCharacter.MapY));
                Point LastPosition = new Point();
                Point NewPosition = new Point();
                LastPosition.X = MyCharacter.MapX;
                LastPosition.Y = MyCharacter.MapY;
                foreach (string Move in MoveList)
                {
                    if (Move == "NW")
                    {
                        NewPosition.X = LastPosition.X - 1;
                        NewPosition.Y = LastPosition.Y - 1;
                    }
                    else if (Move == "N")
                    {
                        NewPosition.X = LastPosition.X - 0;
                        NewPosition.Y = LastPosition.Y - 1;
                    }
                    else if (Move == "NE")
                    {
                        NewPosition.X = LastPosition.X + 1;
                        NewPosition.Y = LastPosition.Y - 1;
                    }
                    else if (Move == "E")
                    {
                        NewPosition.X = LastPosition.X + 1;
                        NewPosition.Y = LastPosition.Y - 0;
                    }
                    else if (Move == "SE")
                    {
                        NewPosition.X = LastPosition.X + 1;
                        NewPosition.Y = LastPosition.Y + 1;
                    }
                    else if (Move == "S")
                    {
                        NewPosition.X = LastPosition.X + 0;
                        NewPosition.Y = LastPosition.Y + 1;
                    }
                    else if (Move == "SW")
                    {
                        NewPosition.X = LastPosition.X - 1;
                        NewPosition.Y = LastPosition.Y + 1;
                    }
                    else if (Move == "W")
                    {
                        NewPosition.X = LastPosition.X - 1;
                        NewPosition.Y = LastPosition.Y + 0;
                    }
                    LastPosition = NewPosition;
                    Positions.Add(NewPosition);
                }

                //List of tiles that are in our move list
                List<MapItem> MapPositions = new List<MapItem>();
                List<Character> CharactersWithin12 = new List<Character>();

                foreach (MapItem mapitem in MyCharacter.currentMapItem.mapItemsWithin12)
                {
                    foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                    {
                        if (creaturebase is Character)
                            CharactersWithin12.Add((Character)creaturebase);
                    }
                    //Find MapItems in move list
                    if (Math.Abs(mapitem.MapX - MyCharacter.MapX) <= 4 && Math.Abs(mapitem.MapY - MyCharacter.MapY) <= 4)
                    {
                        //Do not break this loop incase the same tile is in our path more than once
                        foreach (Point position in Positions)
                        {
                            if (position.X == mapitem.MapX && position.Y == mapitem.MapY)
                                MapPositions.Add(mapitem);
                        }
                    }
                    //Get creature to attack
                    if (mapitem.MapX == LastPosition.X && mapitem.MapY == LastPosition.Y)
                    {
                        if (CreatureID != -1)
                        {
                            foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                            {
                                if (creaturebase.CreatureID == CreatureID && creaturebase.HP > 0)
                                {
                                    CritToAttack = creaturebase;
                                    break;
                                }
                            }

                            if (CritToAttack == null)
                            {
                                MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                                MyCharacter.SendMessage("Cannot find target creature", "server");
                                MyCharacter.SetBusy(false);
                                return "true";
                            }
                        }
                    }
                }
                
                //Order map positions
                List<MapItem> orderedPositions = new List<MapItem>();
                foreach (Point position in Positions)
                {
                    foreach (MapItem mapitem in MapPositions)
                    {
                        if (mapitem.MapX == position.X && mapitem.MapY == position.Y)
                        {
                            orderedPositions.Add(mapitem);
                            break;
                        }
                    }
                }
                MapPositions = orderedPositions;


                //Check to see if path leads to a portal, we might need to make a server transfer request
                if (isPortal == false)
                {
                    MapItem PortalMapItem = null;
                    int NumMovesAvail2 = Positions.Count;
                    for (int x = 0; x < NumMovesAvail2; x++)
                    {
                        foreach (MapItem mapitem in MapPositions)
                        {
                            if (mapitem.MapX == Positions[x].X && mapitem.MapY == Positions[x].Y)
                            {
                                //Check Hex Motion and reduce max turns
                                if (mapitem.CreatureMotion() + 1 < NumMovesAvail2)
                                    NumMovesAvail2 = mapitem.CreatureMotion() + 1;

                                if (mapitem.CreatureMotion() == 0)
                                {
                                    NumMovesAvail2 = 0;
                                    break;
                                }
                                if (mapitem.TerrainType == "Air" || mapitem.TerrainType == "RopeDown")
                                {
                                    PortalMapItem = mapitem;
                                    NumMovesAvail2 = 0;
                                    break;
                                }
                                break;
                            }
                        }
                    }

                    if (PortalMapItem != null)
                    {
                        //If this server does not own the map we're moving to, end this function and wait
                        //For the response from primary server to move the character
                        if (Managers.localWorldsManager.ownsWorld(PortalMapItem.PortalMapID, MyCharacter.Instance) == false)
                        {
                            //Make transfer character request
                            TransferCharacterRequestWS transferRequest = new TransferCharacterRequestWS();
                            transferRequest.character = MyCharacter;
                            transferRequest.MapID = PortalMapItem.PortalMapID;
                            transferRequest.Instance = MyCharacter.Instance;
                            transferRequest.MapX = PortalMapItem.PortalX;
                            transferRequest.MapY = PortalMapItem.PortalY;
                            transferRequest.MoveList = MoveList;
                            transferRequest.PortalDistance = PortalMapItem.PortalDistance;
                            transferRequest.isPush = isPush;

                            //TODO: Add portal sound
                            transferRequest.PortalSound = "";

                            //If send to primary fails
                            if (Managers.transferCharacterManager.SendTransferRequest(transferRequest) == false)
                            {
                                MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                                return "Map is currently unavailable";
                            }

                            return "";
                        }

                    }
                }

                //Check Movements & Choose Destination
                List<MapItem> MapItemsToUpdate = new List<MapItem>();
                LastPosition.X = MyCharacter.MapX;
                LastPosition.Y = MyCharacter.MapY;

                //This will be the tile we land on after move calculations
                MapItem LastMapItem = MyCharacter.currentMapItem;

                int NumMovesAvail = Positions.Count;

                List<string> SoundsPlayed = new List<string>();

                for (int x = 0; x < NumMovesAvail; x++)
                {
                    MapItem mapitem = MapPositions[x];
                    
                    //Check Hex Motion and reduce max turns
                    int allowedMotion = mapitem.CreatureMotion();
                    if (mapitem.TerrainType == "Water" && MyCharacter.equipManager.WaterMotion() > allowedMotion)
                        allowedMotion = MyCharacter.equipManager.WaterMotion();

                    allowedMotion = allowedMotion + 1;

                    if (allowedMotion < NumMovesAvail)
                        NumMovesAvail = allowedMotion;

                    NewPosition2.X = mapitem.MapX;
                    NewPosition2.Y = mapitem.MapY;

                    if (mapitem.CreatureMotion() == 0)
                    {
                        NewPosition2.X = LastPosition.X;
                        NewPosition2.Y = LastPosition.Y;

                        string rootMessage = mapitem.GetRootMessage();
                        if (rootMessage == "")
                        {
                            Spell_WallStun wallstun = new Spell_WallStun();
                            CreatureBase targetCreaturebase = (CreatureBase)MyCharacter;
                            wallstun.Cast(targetCreaturebase);

                            //Play Thump Sound
                            foreach (Character character in CharactersWithin12)
                                character.PlaySound("Thump", NewPosition2.X, NewPosition2.Y);
                        }
                        else
                        {
                            Message msg = new Message();
                            msg.Type = "server";
                            msg.CreatureID = MyCharacter.CreatureID;
                            msg.Text = rootMessage;
                            MyCharacter.AddMessage(msg);

                            MyCharacter.PlaySound("Ding", NewPosition2.X, NewPosition2.Y);
                        }

                        break;
                    }
                    if (mapitem.TerrainType == "Air" || mapitem.TerrainType == "RopeDown")
                    {
                        //If portaling to same map id, set the destination to the portal mapitem
                        //We have no idea where this portal goes to, so we have to scan the whole map.
                        if (mapitem.PortalMapID == MyCharacter.MapID)
                        {
                            LastMapItem = GetMap(MyCharacter.MapID, MyCharacter.Instance).GetMapItem(mapitem.PortalX, mapitem.PortalY);

                            //Merge the characters at our portal drop with the characters at our portal from (they will both get sent all the updates for simplicity)
                            List<Character> charactersNearPortalDrop = LastMapItem.getCharactersWithin8();
                            foreach (Character portalCharacter in charactersNearPortalDrop)
                            {
                                if (CharactersWithin12.Contains(portalCharacter) == false)
                                    CharactersWithin12.Add(portalCharacter);
                            }
                        }

                        NewMapID = mapitem.PortalMapID;
                        NewPosition2.X = mapitem.PortalX;
                        NewPosition2.Y = mapitem.PortalY;
                        NumMovesAvail = 0;

                        if (isPortal == false && mapitem.PortalDistance > 0)
                        {
                            Message message = new Message();
                            message.CreatureID = MyCharacter.CreatureID;
                            message.Text = "You have fallen! (" + System.Convert.ToString(mapitem.PortalDistance * 10) + ")";

                            if (MyCharacter.buffManager.HasFeatherFall() == false)
                            {
                                message.Type = "damaged";
                                MyCharacter.HP = MyCharacter.HP - (mapitem.PortalDistance * 10);
                            }
                            else
                                message.Type = "damage";

                            MyCharacter.AddMessage(message);
                        }

                        break;
                    }
                    //Open Door If Closed
                    else if (mapitem.TerrainType == "Door")
                    {
                        if (mapitem.TerrainUrl.IndexOf("Closed") > 0)
                        {
                            mapitem.Transparent = true;
                            mapitem.TerrainUrl = mapitem.TerrainUrl.Replace("Closed", "Open");
                            MapItemsToUpdate.Add(mapitem);

                            bool foundSound = false;
                            foreach (string sound in SoundsPlayed)
                            {
                                if (sound == "DoorOpen")
                                {
                                    foundSound = true;
                                    break;
                                }
                            }
                            if (foundSound == false)
                            {
                                SoundsPlayed.Add("DoorOpen");
                                foreach (Character character in CharactersWithin12)
                                {
                                    if (Math.Abs(character.MapX - mapitem.MapX) <= 8 && Math.Abs(character.MapY - mapitem.MapY) <= 8)
                                        character.PlaySound("DoorOpen", mapitem.MapX, mapitem.MapY);
                                }
                            }
                        }
                    }
                    else if (mapitem.TerrainType == "Water" && x != 0)
                    {
                        //Play Splash Sound
                        bool foundSound = false;
                        foreach (string sound in SoundsPlayed)
                        {
                            if (sound == "Splash")
                            {
                                foundSound = true;
                                break;
                            }
                        }
                        if (foundSound == false)
                        {
                            SoundsPlayed.Add("Splash");
                            foreach (Character character in CharactersWithin12)
                            {
                                if (Math.Abs(character.MapX - mapitem.MapX) <= 8 && Math.Abs(character.MapY - mapitem.MapY) <= 8)
                                    character.PlaySound("Splash", mapitem.MapX, mapitem.MapY);
                            }
                        }
                    }
                    LastPosition.X = mapitem.MapX;
                    LastPosition.Y = mapitem.MapY;
                    LastMapItem = mapitem;
                }

                MyCharacter.currentMapItem.CreaturesBases.Remove(MyCharacter);
                MapItemsToUpdate.Add(MyCharacter.currentMapItem);

                if (NewMapID == MyCharacter.MapID)
                {
                    //Get distance to destination tile
                    int moveDistance = MapPositions.IndexOf(LastMapItem);
                    //Apply overweight stamina penalty
                    if (MyCharacter.get0verweightBy() > 0 && isPush == false)
                    {
                        int overWeightBy = System.Convert.ToInt32(MyCharacter.get0verweightBy());
                        int stamCost = 0;

                        if (moveDistance == 4)
                            stamCost = overWeightBy;
                        else if (moveDistance == 3)
                            stamCost = System.Convert.ToInt32(overWeightBy * .6);
                        else if (moveDistance == 2)
                            stamCost = System.Convert.ToInt32(overWeightBy * .3);

                        MyCharacter.Stamina = MyCharacter.Stamina - stamCost;
                    }
                    

                    //Add Character
                    MyCharacter.SetPosition(LastMapItem);
                    LastMapItem.CreaturesBases.Add(MyCharacter);
                    MapItemsToUpdate.Add(LastMapItem);

                    Buff hide = MyCharacter.buffManager.GetBuffByStackType("Hide");
                    bool removeHide = hide == null ? false : true;

                    //See if we need to remove hide
                    foreach (MapItem mapitem in LastMapItem.mapItemsWithin4)
                    {
                        //If we have a hide spell on, see if there is terrain or not
                        if (removeHide == true)
                        {
                            if ((Math.Abs(mapitem.MapX - MyCharacter.MapX) <= 1 && Math.Abs(mapitem.MapY - MyCharacter.MapY) <= 1 && mapitem.TerrainUrl != "") ||
                                (mapitem.MapX == MyCharacter.MapX && mapitem.MapY == MyCharacter.MapY && mapitem.isDark(null) == true))
                            {
                                removeHide = false;
                                break;
                            }
                        } 
                    }
                    if (removeHide == true)
                        hide.RemoveSpell(true, true);

                    //Send MyCharacter Update (Position Changed)
                    MyCharacter.Update_Character();
                    MyCharacter.AddMapItems(LastMapItem.mapItemsWithin8, true);
                }

                foreach (Character character in CharactersWithin12)
                {
                    foreach (MapItem mItem in MapItemsToUpdate)
                    {
                        if (Math.Abs(character.MapX - mItem.MapX) <= 8 && Math.Abs(character.MapY - mItem.MapY) <= 8)
                        {
                            if (character != MyCharacter)
                                character.AddMapItems(MapItemsToUpdate, false);

                            break;
                        }
                    }
                }

                 if (isPortal == true && NewMapID != MyCharacter.MapID)
                     return "";

                 if (MyCharacter.HP < 1)
                 {
                     MyCharacter.DropLoot(-1);
                     MyCharacter.PlaySound(MyCharacter.SoundDeath, MyCharacter.MapX, MyCharacter.MapY);
                     MyCharacter.Timer_Respawn.Start();

                     Message message = new Message();
                     message.CreatureID = MyCharacter.CreatureID;
                     message.Type = "slain";
                     message.Text = "You have fallen to your death!";

                     MyCharacter.AddMessage(message);
                 }


                 //Perform rush attack
                 if (MyCharacter.HP > 0 && CritToAttack != null && CritToAttack.HP > 0 && CritToAttack.currentMapItem == LastMapItem)
                 {
                     int AtkDelay;
                     bool attackSuccess = MyCharacter.AttackCreatureBase(CritToAttack, true, out AtkDelay) > 0 ? true : false;

                     if (attackSuccess == true)
                     {
                         CritToAttack.Update_Character();
                         if (CritToAttack.HP < 1)
                         {
                             if (!(CritToAttack is Character))
                                 LastMapItem.CreaturesBases.Remove(CritToAttack);

                             foreach (Character character in CharactersWithin12)
                                 character.AddMapItem(LastMapItem);
                         }
                         else
                         {
                             foreach (Character character in CharactersWithin12)
                                 character.AddCreatureBase(CritToAttack);
                         }
                     }
                     if (AtkDelay != -1)
                         Delay = Delay + AtkDelay;
                 }

                //Function Complete If On Same Map
                if (NewMapID == MyCharacter.MapID)
                {
                    Map CurrentMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);

                    CurrentMap.LootMngr.GetLootInArea(MyCharacter);

                    if (isPush == false)
                    {
                        MyCharacter.Timer_Round_Interval = System.Convert.ToDouble(Delay);
                        MyCharacter.Timer_Round_Start();
                    }

                    return "true";
                }

                //Set this before the lock ends. Any other methods that are waiting for this lock to open for this character
                //Will be stopped and re-invoked when this is set to back to false.
                MyCharacter.setIsChangingMaps(true);

            }// LOCK ENDS HERE

            MyCharacter.MapID = NewMapID;

            //Dont mess with stam if the character is being pushed by something
            if (MyCharacter.getWeight() > MyCharacter.StrengthTotal && isPush == false)
            {
                int overWeightBy = System.Convert.ToInt32(MyCharacter.getWeight() - MyCharacter.StrengthTotal);
                int stamCost = 0;

                if (MoveList.Count == 4)
                    stamCost = overWeightBy;
                else if (MoveList.Count == 3)
                    stamCost = System.Convert.ToInt32(overWeightBy * .6);
                else if (MoveList.Count == 2)
                    stamCost = System.Convert.ToInt32(overWeightBy * .3);

                MyCharacter.Stamina = MyCharacter.Stamina - stamCost;
            }

            //Get Lock
            MyLock = GetLockItem(NewMapID, MyCharacter.Instance);
            lock (MyLock.LockObj)
            {
                //List<MapSound> soundsMap2 = new List<MapSound>();
                List<MapItem> MapItemsToUpdate2 = new List<MapItem>();
                List<MapItem> MyMapItems2 = new List<MapItem>();

                //Get Map
                Map MyMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);
                
                List<Character> CharsToUpdate = new List<Character>();
                foreach (MapItem mapitem in MyMap.MapItems)
                {
                    if (Math.Abs(mapitem.MapX - NewPosition2.X) <= 8 && Math.Abs(mapitem.MapY - NewPosition2.Y) <= 8)
                    {
                        if (mapitem.MapX == NewPosition2.X && mapitem.MapY == NewPosition2.Y)
                        {
                            MyCharacter.SetPosition(mapitem);
                            mapitem.CreaturesBases.Add(MyCharacter);
                            MapItemsToUpdate2.Add(mapitem);
                        }
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                            {
                                Character character = (Character)creatureBase;
                                //Record Nearby Characters
                                if (character.ID != MyCharacter.ID)
                                    CharsToUpdate.Add(character);
                            }
                        }
                        
                        MyMapItems2.Add(mapitem);
                    }
                }
                if (MyCharacter.HP < 1)
                {
                    MyCharacter.DropLoot(-1);
                    MyCharacter.PlaySound(MyCharacter.SoundDeath,MyCharacter.MapX,MyCharacter.MapY);
                    MyCharacter.Timer_Respawn.Start();

                    Message message = new Message();
                    message.CreatureID = MyCharacter.CreatureID;
                    message.Type = "slain";
                    message.Text = "You have fallen to your death!";

                    MyCharacter.AddMessage(message);
                }


                //Send MapItems Update to Nearby Characters
                foreach (Character character in CharsToUpdate)
                {
                    if (character != MyCharacter)
                        character.AddMapItems(MapItemsToUpdate2,false);
                    if (MyCharacter.HP < 1)
                        character.PlaySound(MyCharacter.SoundDeath, MyCharacter.MapX, MyCharacter.MapY);
                }
                MyCharacter.Update_Character(); //Update MyCharacter 
                MyCharacter.AddMapItems(MyMapItems2, true); //Update My Map

                MyMap.LootMngr.GetLootInArea(MyCharacter);

                //Release the map transfer. This will invoke any other methods that got stopped due to the map transfer.
                MyCharacter.setIsChangingMaps(false);

            }//End lock

            if (isPush == false)
            {
                MyCharacter.Timer_Round_Interval = System.Convert.ToDouble(Delay);
                MyCharacter.Timer_Round_Start();
            }

            return "true";
            
        }
        
        public string OpenCloseDoor(Character MyCharacter, string Action, int MapX, int MapY)
        {
            //Get Lock
            LockItem MyLock = GetLockItem(MyCharacter.MapID, MyCharacter.Instance);

            List<Character> CharsToUpdate = new List<Character>();
            List<MapItem> MapItemsToUpdate = new List<MapItem>();

            AppHandler2 app = this;

            lock (MyLock.LockObj)
            {
                //Get Map
                List<MapSound> soundsToPlay = new List<MapSound>();
                MapSound soundToPlay = new MapSound();
                Map MyMap = GetMap(MyCharacter.MapID,MyCharacter.Instance);
                
                foreach (MapItem mapitem in MyMap.MapItems)
                {
                    if (mapitem.MapX - MapX >= -8 && mapitem.MapX - MapX <= 8 && mapitem.MapY - MapY >= -8 && mapitem.MapY - MapY <= 8)
                    {
                        foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                        {
                            if (creatureBase is Character)
                                CharsToUpdate.Add((Character)creatureBase);
                        }
                    }
                    if (mapitem.MapX == MapX && mapitem.MapY == MapY)
                    {
                        if (Action == "Open")
                        {
                            if (mapitem.TerrainUrl.IndexOf("Open") != -1)
                            {
                                return "Door Is Already Open";
                            }
                            if (mapitem.TerrainType == "Door")
                            {
                                mapitem.Transparent = true;
                                mapitem.TerrainUrl = mapitem.TerrainUrl.Replace("Closed", "Open");

                                //Play Sound Door Open
                                soundToPlay = new MapSound();
                                soundToPlay.Name = "DoorOpen";
                                soundToPlay.MapX = mapitem.MapX;
                                soundToPlay.MapY = mapitem.MapY;
                                soundsToPlay.Add(soundToPlay);
                            }
                            else if (mapitem.TerrainType == "Wall" || mapitem.TerrainType == "SDoor")
                            {
                                if (MyCharacter.Gender == "Male")
                                {
                                    //Play Sound Male Hmmm
                                    soundToPlay = new MapSound();
                                    soundToPlay.Name = "MaleHmm";
                                    soundToPlay.MapX = mapitem.MapX;
                                    soundToPlay.MapY = mapitem.MapY;
                                    soundsToPlay.Add(soundToPlay);
                                }
                                else
                                {
                                    //Play Sound Femal Hmmm
                                    soundToPlay = new MapSound();
                                    soundToPlay.Name = "FemaleHmm";
                                    soundToPlay.MapX = mapitem.MapX;
                                    soundToPlay.MapY = mapitem.MapY;
                                    soundsToPlay.Add(soundToPlay);
                                }
                                if (mapitem.TerrainType == "SDoor")
                                {
                                    mapitem.Transparent = true;
                                    mapitem.Motion = 4;
                                    mapitem.TerrainUrl = mapitem.TerrainUrl + "_Open";

                                    //Play Sound Door Open
                                    soundToPlay = new MapSound();
                                    soundToPlay.Name = "DoorOpen";
                                    soundToPlay.MapX = mapitem.MapX;
                                    soundToPlay.MapY = mapitem.MapY;
                                    soundsToPlay.Add(soundToPlay);

                                    mapitem.timerHexReset.Stop();
                                    mapitem.timerHexReset.Start();
                                }
                            }
                        }
                        else //Close
                        {
                            if (mapitem.TerrainUrl.IndexOf("Open") == -1)
                            {
                                return "Door Is Already Closed";
                            }
                            if (mapitem.TerrainType == "Door")
                            {
                                if (mapitem.CreaturesBases.Count > 0)
                                    return "Doorway Blocked";

                                mapitem.Transparent = false;
                                mapitem.TerrainUrl = mapitem.TerrainUrl.Replace("Open", "Closed");

                                //Play Sound Door Closed
                                soundToPlay = new MapSound();
                                soundToPlay.Name = "DoorClose";
                                soundToPlay.MapX = mapitem.MapX;
                                soundToPlay.MapY = mapitem.MapY;
                                soundsToPlay.Add(soundToPlay);
                            }
                            else if (mapitem.TerrainType == "SDoor")
                            {
                                if (mapitem.CreaturesBases.Count > 0)
                                    return "Doorway Blocked";

                                mapitem.Transparent = false;
                                mapitem.Motion = 0;
                                mapitem.TerrainUrl = mapitem.TerrainUrl.Replace("_Open", "");

                                //Play Sound Door Closed
                                soundToPlay = new MapSound();
                                soundToPlay.Name = "DoorClose";
                                soundToPlay.MapX = mapitem.MapX;
                                soundToPlay.MapY = mapitem.MapY;
                                soundsToPlay.Add(soundToPlay);
                            }
                        }
                        MapItemsToUpdate.Add(mapitem);
                    }
                }
                foreach (Character character in CharsToUpdate)
                {
                    character.AddMapItems(MapItemsToUpdate, false);
                    foreach (MapSound mapsound in soundsToPlay)
                    {
                        character.PlaySound(mapsound.Name, mapsound.MapX, mapsound.MapY);
                    }
                }

            }// End Lock

            MyCharacter.Timer_Round_Interval = 2000;
            MyCharacter.Timer_Round_Start();
            return "true";
        }
        public void Spell_RemoveBuff(Character myCharacter, long SpellID)
        {
            LockItem lockItem = GetLockItem(myCharacter.MapID, myCharacter.Instance);

            lock (lockItem.LockObj)
            {
                Buff buff = myCharacter.buffManager.GetBuff(SpellID);
                if (buff != null && buff.spellIcon.Offensive == false)
                {
                    buff.RemoveSpell(true, true);
                    myCharacter.Timer_Round_Interval = 1000;
                    myCharacter.Timer_Round_Start();
                }
                else
                {
                    myCharacter.PlaySound("Ding", myCharacter.MapX, myCharacter.MapY);

                    Message msg = new Message();
                    msg.CreatureID = myCharacter.CreatureID;
                    msg.Type = "server";
                    msg.Text = "Cannot find spell";

                    myCharacter.AddMessage(msg);
                    myCharacter.SetBusy(false);
                }
            }
        }
        public string Spell_Warm(Character myCharacter, int ID_DB)
        {
            LockItem lockItem = GetLockItem(myCharacter.MapID, myCharacter.Instance);
            lock (lockItem.LockObj)
            {
                if (myCharacter.buffManager.IsSilenced() == true)
                {
                    myCharacter.PlaySound("Ding", myCharacter.MapX, myCharacter.MapY);
                    return "You cannot warm spells while silenced!";
                }

                SpellIcon warmSpell = Spells[ID_DB];
                //TODO: Add check to make sure character actually owns this spell

                if (myCharacter.Mana < warmSpell.ManaCost)
                {
                    myCharacter.PlaySound("Ding", myCharacter.MapX, myCharacter.MapY);
                    return "Not enough mana";
                }

                myCharacter.WarmSpell = Spells[ID_DB];
                myCharacter.Update_Character();

                Buff invis = myCharacter.buffManager.GetBuff("Invisibility");
                if (invis != null) invis.RemoveSpell(true, true);

                Buff hide = myCharacter.buffManager.GetBuffByStackType("Hide");
                if (hide != null && myCharacter.WarmSpell.Skill != "Shadow") hide.RemoveSpell(true, true);

                myCharacter.Timer_Round_Interval = 3000 + (3000 * (myCharacter.CastingSpeedPercentModifier / 100.00));
                myCharacter.Timer_Round_Start();

                List<MapItem> MapItemsWithin4 = new List<MapItem>();
                Map CurrentMap = GetMap(myCharacter.MapID,myCharacter.Instance);
                foreach (MapItem mapitem in CurrentMap.MapItems)
                {
                    if (Math.Abs(mapitem.MapX - myCharacter.MapX) <= 8 && Math.Abs(mapitem.MapY - myCharacter.MapY) <= 8)
                    {
                        foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                        {
                            if (creaturebase is Character)
                            {
                                Character character = (Character)creaturebase;
                                character.PlaySound("SpellConjure", myCharacter.MapX, myCharacter.MapY);

                            }
                        }
                    }

                    if (Math.Abs(mapitem.MapX - myCharacter.MapX) <= 4 && Math.Abs(mapitem.MapY - myCharacter.MapY) <= 4)
                        MapItemsWithin4.Add(mapitem);
                }

                Message msg = new Message();
                msg.CreatureID = myCharacter.CreatureID;
                msg.Type = "server";
                msg.Text = myCharacter.Name + " conjures a spell";

                myCharacter.MessageBroadcast(MapItemsWithin4, msg, true);
            }
           
            return "true";
        }

        public string Spell_Fizzle(Character character)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);

            List<Character> CharsWithin8 = new List<Character>();
            lock (lockItem)
            {
                if (character.WarmSpell != null)
                {
                    Map CurrentMap = GetMap(character.MapID, character.Instance);
                    foreach (MapItem mapitem in CurrentMap.MapItems)
                    {
                        if (Math.Abs(mapitem.MapX - character.MapX) <= 8 && Math.Abs(mapitem.MapY - character.MapY) <= 8)
                        {
                            foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                            {
                                if (creaturebase is Character)
                                    CharsWithin8.Add((Character)creaturebase);
                            }
                        }
                    }
                }
                character.WarmSpell = null;
                character.Update_Character();

                foreach (Character charInRange in CharsWithin8)
                {
                    charInRange.PlaySound("SpellFizzle", character.MapX, character.MapY);
                }
            }
            
            return "true";
        }

        public void Spell_CastTarget(Character character, long CreatureGUID)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            
            lock (lockItem.LockObj)
            {
                if (character.WarmSpell == null)
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Server: Spell is not ready";
                    character.AddMessage(message);

                    character.PlaySound("Ding", character.MapX, character.MapY);

                    character.SetBusy(false);

                    return;
                }
                if (character.WarmSpell.CastType != "Target")
                {
                    Message message = new Message();
                    message.CreatureID = character.CreatureID;
                    message.Type = "server";
                    message.Text = "Server: Spell is not a target spell";
                    character.AddMessage(message);

                    character.PlaySound("Ding", character.MapX, character.MapY);

                    character.SetBusy(false);

                    return;
                }
                else
                {
                    Assembly assembly = Assembly.GetExecutingAssembly();
                    string fullTypeName = "Reborn_Server.App1AppHandler" + "." + character.WarmSpell.ClassName;
                    Type myType = assembly.GetType(fullTypeName);

                    object ClassObj = Activator.CreateInstance(myType);

                    int castLevel = System.Convert.ToInt32(Math.Floor(character.skillManager.GetCurrentLevel(character.WarmSpell.Skill)));

                    Object[] args = { character, castLevel, CreatureGUID };
                    object Result = myType.InvokeMember("Cast", BindingFlags.Default | BindingFlags.InvokeMethod, null, ClassObj, args);
                }
            }
        }

        public string Spell_CastSelf(Character character)
        {
            LockItem lockitem = GetLockItem(character.MapID, character.Instance);
            
            string SpellClass = "";
            lock (lockitem.LockObj)
            {
                if (character.WarmSpell == null)
                    return "Spell is not warmed";
                else if (character.WarmSpell.CastType != "Self")
                    return "Spell is not a self cast spell! Quit Hacking!";

                SpellClass = character.WarmSpell.ClassName;

                Assembly assembly = Assembly.GetExecutingAssembly();
                string fullTypeName = "Reborn_Server.App1AppHandler" + "." + SpellClass;
                Type myType = assembly.GetType(fullTypeName);

                object ClassObj = Activator.CreateInstance(myType);

                int castLevel = System.Convert.ToInt32(Math.Floor(character.skillManager.GetCurrentLevel(character.WarmSpell.Skill)));

                Object[] args = { character, castLevel, character.CreatureID };
                object Result = myType.InvokeMember("Cast", BindingFlags.Default | BindingFlags.InvokeMethod, null, ClassObj, args);

                return "true";
            }
        }

        public void Spell_CastArea(Character character, List<string> MoveList)
        {
            LockItem lockItem = GetLockItem(character.MapID, character.Instance);
            lock (lockItem.LockObj)
            {
                if (character.WarmSpell == null)
                {
                    Message msg = new Message();
                    msg.CreatureID = character.CreatureID;
                    msg.Type = "server";
                    msg.Text = "Server: Spell is not conjured";

                    character.AddMessage(msg);
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    character.SetBusy(false);

                    return;
                }
                if (character.WarmSpell.CastType != "Area")
                {
                    Message msg = new Message();
                    msg.CreatureID = character.CreatureID;
                    msg.Type = "server";
                    msg.Text = "Server: Spell is not an area spell!";

                    character.AddMessage(msg);
                    character.PlaySound("Ding", character.MapX, character.MapY);
                    character.SetBusy(false);

                    return;
                }

                Assembly assembly = Assembly.GetExecutingAssembly();
                string fullTypeName = "Reborn_Server.App1AppHandler" + "." + character.WarmSpell.ClassName;
                Type myType = assembly.GetType(fullTypeName);

                object ClassObj = Activator.CreateInstance(myType);

                int castLevel = System.Convert.ToInt32(Math.Floor(character.skillManager.GetCurrentLevel(character.WarmSpell.Skill)));

                Object[] args = { character, castLevel, MoveList };
                object Result = myType.InvokeMember("Cast", BindingFlags.Default | BindingFlags.InvokeMethod, null, ClassObj, args);

            }//End Lock
        }
        public void ChangeColor(Character character, string color)
        {
            LockItem lockitem = GetLockItem(character.MapID, character.Instance);

            lock (lockitem.LockObj)
            {
                if (character.ImageURL.IndexOf("Green") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("Green", color);
                }
                else if (character.ImageURL.IndexOf("Blue") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("Blue", color);
                }
                else if (character.ImageURL.IndexOf("Red",character.ImageURL.Length - 5) > -1)
                {
                    character.ImageURL = character.ImageURL.Substring(0,character.ImageURL.Length - 3) + color;
                }
                else if (character.ImageURL.IndexOf("Purple") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("Purple", color);
                }
                else if (character.ImageURL.IndexOf("White") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("White", color);
                }
                else if (character.ImageURL.IndexOf("Yellow") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("Yellow", color);
                }
                else if (character.ImageURL.IndexOf("Orange") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("Orange", color);
                }
                else if (character.ImageURL.IndexOf("Black") > -1)
                {
                    character.ImageURL = character.ImageURL.Replace("Black", color);
                }
                else
                {
                    character.ImageURL = character.ImageURL + color;
                }
                Map CurrentMap = GetMap(character.MapID, character.Instance);
                {
                    MapItem mapitemToUpdate = null;
                    List<Character> CharsToUpdate = new List<Character>();
                    foreach (MapItem mapitem in CurrentMap.MapItems)
                    {
                        if (Math.Abs(mapitem.MapX - character.MapX) <= 8 && Math.Abs(mapitem.MapY - character.MapY) <= 8)
                        {
                            if (mapitem.MapX == character.MapX && mapitem.MapY == character.MapY)
                                mapitemToUpdate = mapitem;

                            foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                            {
                                if (creaturebase is Character)
                                    CharsToUpdate.Add((Character)creaturebase);
                            }
                        }
                    }
                    foreach (Character ctr in CharsToUpdate)
                    {
                        ctr.AddMapItem(mapitemToUpdate);
                    }
                }
            }//End Lock
        }

        public string MoveCoins(Character MyCharacter, string ItemSource, int ItemX, int ItemY, string ItemDestination, int numCoins)
        {
            try
            {
                AppHandler2 app = this;

                Map CurrentMap = GetMap(MyCharacter.MapID, MyCharacter.Instance);

                //Remove Coins
                bool updateCharacter = false;
                if (ItemSource == "Character")
                {
                    if (MyCharacter.Coins < numCoins)
                    {
                        MyCharacter.SetBusy(false);

                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        MyCharacter.SendMessage("Not enough coins", "server");

                        return "Insufficient Coins (Loot)";
                    }

                    MyCharacter.Coins = MyCharacter.Coins - numCoins;
                    updateCharacter = true;
                }
                else if (ItemSource == "Ground")
                {
                    if (CurrentMap.LootMngr.TakeCoins(ItemX, ItemY, numCoins) == false)
                    {
                        MyCharacter.SetBusy(false);

                        MyCharacter.PlaySound("Ding", MyCharacter.MapX, MyCharacter.MapY);
                        MyCharacter.SendMessage("Not enough coins", "server");

                        return "Insufficient Coins (Ground)";
                    }
                }
                //Add Coins
                if (ItemDestination == "Character")
                {
                    MyCharacter.Coins = MyCharacter.Coins + numCoins;
                    updateCharacter = true;
                }
                else if (ItemDestination == "Ground")
                {
                    CurrentMap.LootMngr.DropCoins(ItemX, ItemY, numCoins, true);
                }
                if (updateCharacter == true)
                {
                    MyCharacter.Update_Character();
                    MyCharacter.updateWeight();
                }

                MyCharacter.Timer_Round_Interval = 1100;
                MyCharacter.Timer_Round_Start();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return "true";
        }

        public void SendTell(Character fromCharacter, string ToName, string Text, string itemLinksXml)
        {
            AppHandler2 app = this;

            Character toCharacter = Managers.characterManager.getCharacter(ToName);

            //Character is not on this server, send to primary server to see if they can be located elsewhere
            if (toCharacter == null)
            {
                TellRequestWS tellRequest = new TellRequestWS();
                tellRequest.fromCharacter = fromCharacter;
                tellRequest.toCharacterName = ToName;
                tellRequest.message = Text;
                tellRequest.itemLinksXml = itemLinksXml;

                //If send to primary fails, send error message to client
                if (Managers.tellManager.sendRequest(tellRequest) == false)
                    fromCharacter.SendMessage("Server: Cannot find " + ToName, "server");

                return;
            }

            Message toMessage = new Message();
            toMessage.CreatureID = fromCharacter.CreatureID;
            toMessage.Text = fromCharacter.Name + " tells you: " + Text;
            toMessage.Type = "tell";
            toMessage.itemLinksXml = itemLinksXml;

            Message returnMessage = new Message();
            returnMessage.CreatureID = toMessage.CreatureID = fromCharacter.CreatureID;
            returnMessage.Text = "You tell " + toCharacter.Name + ": " + Text;
            returnMessage.Type = "tell";
            returnMessage.itemLinksXml = itemLinksXml;

            toCharacter.AddMessage(toMessage);
            fromCharacter.AddMessage(returnMessage);
        }

        public void SetPasswordByID(int UserID, string newPassword)
        {
            SqlConnection MyCon = new SqlConnection(Managers.DBConnectionString);
            SqlCommand SQLCom = new SqlCommand("Users_ChangePasswordByID", MyCon);
            SQLCom.CommandType = System.Data.CommandType.StoredProcedure;

            SQLCom.Parameters.AddWithValue("@ID", UserID);
            SQLCom.Parameters.AddWithValue("@NewPassword", newPassword);

            MyCon.Open();
            SQLCom.ExecuteNonQuery();
            MyCon.Close();
            MyCon.Dispose();
        }

        public void SendSay(Character fromCharacter, string Text, string itemLinksXml)
        {
            Message message = new Message();
            message.CreatureID = fromCharacter.CreatureID;
            message.Text = fromCharacter.Name + " says: " + Text;
            message.Type = "say";
            message.itemLinksXml = itemLinksXml;

            LockItem lockItem = GetLockItem(fromCharacter.MapID, fromCharacter.Instance);

            lock (lockItem.LockObj)
            {
                List<Point> Hidden = CreatureAI.FindHidden(fromCharacter, fromCharacter.currentMapItem.mapItemsWithin4, true);

                List<MapItem> MapItemsNotHidden = new List<MapItem>();
                foreach (MapItem mapitem in fromCharacter.currentMapItem.mapItemsWithin4)
                {
                    bool foundHidden = false;
                    foreach (Point point in Hidden)
                    {
                        if (point.X == mapitem.MapX && point.Y == mapitem.MapY)
                        {
                            foundHidden = true;
                            break;
                        }
                    }
                    if (foundHidden == false)
                        MapItemsNotHidden.Add(mapitem);
                }
                foreach (MapItem mapitem in MapItemsNotHidden)
                {
                    foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                    {
                        if (creatureBase is Character)
                        {
                            Character character = (Character)creatureBase;
                            character.AddMessage(message);
                        }
                    }
                }
            }
        }

        public void SendShout(Character fromCharacter, string Text, string itemLinksXml)
        {
            Message message = new Message();
            message.CreatureID = fromCharacter.CreatureID;
            message.Type = "shout";
            message.itemLinksXml = itemLinksXml;

            LockItem lockItem = GetLockItem(fromCharacter.MapID, fromCharacter.Instance);

            lock (lockItem.LockObj)
            {
                foreach (MapItem mapitem in fromCharacter.currentMapItem.mapItemsWithin12)
                {
                    foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                    {
                        if (creaturebase is Character)
                        {
                            string Direction = MapItem.getDirection(mapitem, fromCharacter.currentMapItem);
                            if (Direction == "")
                                message.Text = fromCharacter.Name + " shouts: " + Text;
                            else
                                message.Text = fromCharacter.Name + " shouts from the " + Direction + ": " + Text;

                            Character character = (Character)creaturebase;
                            character.AddMessage(message);
                        }
                    }
                }
            }
        }

        public void Pet_ChangeMotion(long CreatureGUID, Character character, string motionType)
        {
            if (motionType == "follow")
                character.petManager.ChangePetMotion(CreatureGUID, Pet_Controller.PetMotion.Follow);
            else if (motionType == "stay")
                character.petManager.ChangePetMotion(CreatureGUID, Pet_Controller.PetMotion.Stay);
            else if (motionType == "dismiss")
                character.petManager.CharacterDismissPet(CreatureGUID);
        }

        public void Pet_Attack(long CreatureGUID, Character character, long AttackCreatureGUID)
        {
            character.petManager.AttackCreature(CreatureGUID, AttackCreatureGUID);
        }

        public void Pet_MoveTo(long CreatureGUID, Character character, int MapX, int MapY)
        {
            character.petManager.MoveTo(CreatureGUID, MapX, MapY);
        }

        public LockItem GetLockItem(int MapID, int Instance)
        {
            return mapLocks.getLockItem(MapID, Instance);

            //lock (LockItems)
            //{
            //    foreach (LockItem lockItem in LockItems)
            //    {
            //        if (lockItem.MapID == MapID && lockItem.MapInstance == Instance)
            //            return lockItem;
            //    }
            //    CreateMap(MapID, Instance);
            //}

            //return GetLockItem(MapID, Instance);
        }
        public Map GetMap(int MapID, int Instance)
        {
            lock (Maps)
            {
                foreach (Map map in Maps)
                {
                    if (map.MapID == MapID && map.MapInstance == Instance)
                        return map;
                }
            }

            //Generate the map if it doesnt exist
            GetLockItem(MapID, Instance);

            return GetMap(MapID, Instance);
        }

        public bool TrySendMessage(string name, string msg, string itemLinksXml, string type)
        {
            Character character = Managers.characterManager.getCharacter(name);
            if (character == null)
                return false;

            Message message = new Message();
            message.itemLinksXml = itemLinksXml;
            message.CreatureID = character.CreatureID;
            message.Type = type;
            message.Text = msg;

            character.AddMessage(message);

            return true;
        }

        public bool TrySendMessage(int CharacterID, string msg, string type)
        {
            return TrySendMessage(CharacterID, msg, "", type);
        }
        public bool TrySendMessage(int CharacterID, string msg, string itemLinksXml, string type)
        {
            if (CharacterID == -1)
                return false;

            Character character = Managers.characterManager.getCharacter(CharacterID);
            if (character != null)
            {
                Message message = new Message();
                message.CreatureID = character.CreatureID;
                message.Type = type;
                message.Text = msg;

                if (itemLinksXml != "")
                    message.itemLinksXml = itemLinksXml;

                character.AddMessage(message);
            }

            return true;
        }

        public SpellIcon getSpellByName(string name)
        {
            foreach (KeyValuePair<int, SpellIcon> item in Spells)
            {
                if (item.Value.Name.ToLower() == name.ToLower())
                    return item.Value.clone();
            }
            return null;
        }

        //overload passes null to CreateItem causing the master item to set the boundTo value
        public Loot CreateItem(int ItemID)
        {
            return CreateItem(ItemID, null);
        }
        public Loot CreateItem(int ItemID, int? boundTo)
        {
            return CreateItem(ItemID, boundTo, false);
        }
        //Creates and binds the item (if it is a binding item)
        public Loot CreateItem(Character bindToCharacter, int ItemID)
        {
            Loot newItem = CreateItem(ItemID);

            if (newItem.BoundTo < -1)
                newItem.BoundTo = bindToCharacter.ID;

            return newItem;
        }
        //boundTo is set if we are generating an item that is already bound (such as when a player logs in)
        public Loot CreateItem(int ItemID, int? boundTo, bool dummyNoGuid)
        {
            AppHandler2 app = this;
            Loot NewItem = null;

            //GET LOOT ITEM FROM SERVER
            Loot ItemMaster = Items[ItemID];
            if (ItemMaster is Weapon)
                NewItem = (Weapon)ItemMaster.Clone();
            else if (ItemMaster is Equipment)
                NewItem = (Equipment)ItemMaster.Clone();
            else if (ItemMaster != null)
                NewItem = (Loot)ItemMaster.Clone();
            else
                return null;

            if (boundTo == null)
                NewItem.BoundTo = ItemMaster.BoundTo;
            else
                NewItem.BoundTo = boundTo.Value;

            if (dummyNoGuid == false)
                NewItem.GameUID = ItemIDGen.GetUID(); //CREATE UNIQUE ID

            return NewItem;
        }
    }
    class MapName
    {
        public string Name;
        public int MapID;
    }
}


